From 91aa5fadb831e7b6ea473a526a6b49c6dc4819ce Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:31:04 +0000 Subject: ARM: PL08x: fix atomic_t usage and tx_submit() return value range The last_issued variable uses an atomic type, which is only incremented inside a protected region, and then read. Everywhere else only reads the value, so it isn't using atomic_t correctly, and it doesn't even need to. Moreover, the DMA engine code provides us with a variable for this already - chan.cookie. Use chan.cookie instead. Also, avoid negative dma_cookie_t values - negative returns from tx_submit() mean failure, yet in reality we always succeed. Restart from cookie 1, just like other DMA engine drivers do. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- include/linux/amba/pl08x.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux/amba') diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 521a0f8974ac..4ae62b4684f9 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -174,7 +174,6 @@ struct pl08x_dma_chan { struct pl08x_channel_data *cd; dma_addr_t runtime_addr; enum dma_data_direction runtime_direction; - atomic_t last_issued; dma_cookie_t lc; struct list_head desc_list; struct pl08x_txd *at; -- cgit v1.2.3 From 7cb72ad959b16ac594118977b7954a7d2ec7a052 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:35:28 +0000 Subject: ARM: PL08x: avoid 'void *' struct fields when we can type them properly Avoid using 'void *' struct fields when the structs are not defined in linux/amba/pl08x.h - instead, forward declare the struct names, and use these instead. This ensures we have proper typechecking. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 16 ++++++++-------- include/linux/amba/pl08x.h | 5 ++++- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 707fa081c9fa..fada97873d7d 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -107,7 +107,7 @@ struct vendor_data { * An LLI struct - see PL08x TRM. Note that next uses bit[0] as a bus bit, * start & end do not - their bus bit info is in cctl. */ -struct lli { +struct pl08x_lli { dma_addr_t src; dma_addr_t dst; dma_addr_t next; @@ -160,7 +160,7 @@ struct pl08x_driver_data { /* Maximum times we call dma_pool_alloc on this pool without freeing */ #define PL08X_MAX_ALLOCS 0x40 -#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct lli)) +#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli)) #define PL08X_ALIGN 8 static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan) @@ -354,8 +354,8 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) * currently active transaction. */ if (ch && txd) { - struct lli *llis_va = txd->llis_va; - struct lli *llis_bus = (struct lli *) txd->llis_bus; + struct pl08x_lli *llis_va = txd->llis_va; + struct pl08x_lli *llis_bus = (struct pl08x_lli *) txd->llis_bus; u32 clli = readl(ch->base + PL080_CH_LLI); /* First get the bytes in the current active LLI */ @@ -558,8 +558,8 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd, int num_llis, int len, u32 cctl, u32 *remainder) { - struct lli *llis_va = txd->llis_va; - struct lli *llis_bus = (struct lli *) txd->llis_bus; + struct pl08x_lli *llis_va = txd->llis_va; + struct pl08x_lli *llis_bus = (struct pl08x_lli *) txd->llis_bus; BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); @@ -620,8 +620,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, u32 cctl; int max_bytes_per_lli; int total_bytes = 0; - struct lli *llis_va; - struct lli *llis_bus; + struct pl08x_lli *llis_va; + struct pl08x_lli *llis_bus; txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 4ae62b4684f9..3ecc20fce26a 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -22,6 +22,9 @@ #include #include +struct pl08x_lli; +struct pl08x_driver_data; + /** * struct pl08x_channel_data - data structure to pass info between * platform and PL08x driver regarding channel configuration @@ -179,7 +182,7 @@ struct pl08x_dma_chan { struct pl08x_txd *at; unsigned long lockflags; spinlock_t lock; - void *host; + struct pl08x_driver_data *host; enum pl08x_dma_chan_state state; bool slave; struct pl08x_txd *waiting; -- cgit v1.2.3 From cace658572ba5d1075f3891e823130a66f3e330f Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:37:31 +0000 Subject: ARM: PL08x: use 'size_t' for lengths Use size_t for variables denoting lengths throughout, and use the 'z' qualifier for printing the value. For safety, add a BUG_ON() in pl08x_fill_lli_for_desc() to catch the remainder potentially becoming negative. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 40 +++++++++++++++++----------------------- include/linux/amba/pl08x.h | 4 ++-- 2 files changed, 19 insertions(+), 25 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 760b71eec84c..fa78697790c0 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -342,7 +342,7 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) struct pl08x_txd *txdi = NULL; struct pl08x_txd *txd; unsigned long flags; - u32 bytes = 0; + size_t bytes = 0; spin_lock_irqsave(&plchan->lock, flags); @@ -470,7 +470,7 @@ static inline unsigned int pl08x_get_bytes_for_cctl(unsigned int coded) } static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, - u32 tsize) + size_t tsize) { u32 retbits = cctl; @@ -583,6 +583,8 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, if (cctl & PL080_CONTROL_DST_INCR) txd->dstbus.addr += len; + BUG_ON(*remainder < len); + *remainder -= len; return num_llis + 1; @@ -591,7 +593,7 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, /* * Return number of bytes to fill to boundary, or len */ -static inline u32 pl08x_pre_boundary(u32 addr, u32 len) +static inline size_t pl08x_pre_boundary(u32 addr, size_t len) { u32 boundary; @@ -614,11 +616,11 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, { struct pl08x_channel_data *cd = txd->cd; struct pl08x_bus_data *mbus, *sbus; - u32 remainder; + size_t remainder; int num_llis = 0; u32 cctl; - int max_bytes_per_lli; - int total_bytes = 0; + size_t max_bytes_per_lli; + size_t total_bytes = 0; struct pl08x_lli *llis_va; txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, @@ -686,13 +688,13 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) * PL080_CONTROL_TRANSFER_SIZE_MASK; dev_vdbg(&pl08x->adev->dev, - "%s max bytes per lli = %d\n", + "%s max bytes per lli = %zu\n", __func__, max_bytes_per_lli); /* We need to count this down to zero */ remainder = txd->len; dev_vdbg(&pl08x->adev->dev, - "%s remainder = %d\n", + "%s remainder = %zu\n", __func__, remainder); /* @@ -760,9 +762,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * width left */ while (remainder > (mbus->buswidth - 1)) { - int lli_len, target_len; - int tsize; - int odd_bytes; + size_t lli_len, target_len, tsize, odd_bytes; /* * If enough left try to send max possible, @@ -805,7 +805,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (lli_len <= 0) { dev_err(&pl08x->adev->dev, - "%s lli_len is %d, <= 0\n", + "%s lli_len is %zu, <= 0\n", __func__, lli_len); return 0; } @@ -853,7 +853,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (target_len != lli_len) { dev_vdbg(&pl08x->adev->dev, - "%s can't send what we want. Desired 0x%08x, lli of 0x%08x bytes in txd of 0x%08x\n", + "%s can't send what we want. Desired 0x%08zx, lli of 0x%08zx bytes in txd of 0x%08zx\n", __func__, target_len, lli_len, txd->len); } @@ -863,7 +863,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, tsize); dev_vdbg(&pl08x->adev->dev, - "%s fill lli with single lli chunk of size 0x%08x (remainder 0x%08x)\n", + "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", __func__, lli_len, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis, lli_len, cctl, @@ -882,7 +882,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, && (remainder); j++) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single byte (remain 0x%08x)\n", + "%s align with boundary, single byte (remain 0x%08zx)\n", __func__, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, @@ -896,16 +896,10 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* * Send any odd bytes */ - if (remainder < 0) { - dev_err(&pl08x->adev->dev, "%s remainder not fitted 0x%08x bytes\n", - __func__, remainder); - return 0; - } - while (remainder) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single odd byte (remain %d)\n", + "%s align with boundary, single odd byte (remain %zu)\n", __func__, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1, cctl, &remainder); @@ -914,7 +908,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } if (total_bytes != txd->len) { dev_err(&pl08x->adev->dev, - "%s size of encoded lli:s don't match total txd, transferred 0x%08x from size 0x%08x\n", + "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n", __func__, total_bytes, txd->len); return 0; } diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 3ecc20fce26a..2c834ed5f41f 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -77,7 +77,7 @@ struct pl08x_bus_data { dma_addr_t addr; u8 maxwidth; u8 buswidth; - u32 fill_bytes; + size_t fill_bytes; }; /** @@ -113,7 +113,7 @@ struct pl08x_txd { enum dma_data_direction direction; struct pl08x_bus_data srcbus; struct pl08x_bus_data dstbus; - int len; + size_t len; dma_addr_t llis_bus; void *llis_va; struct pl08x_channel_data *cd; -- cgit v1.2.3 From 19524d77ec34faf58d313ba34fb755ef6e159216 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:39:13 +0000 Subject: ARM: PL08x: avoid duplicating registers in txd and phychan structures As we now have all the code accessing the phychan {csrc,cdst,clli,cctl, ccfg} members in one function, there's no point storing the data into the struct. Get rid of the struct members. Re-order the register dump in the dev_dbg() to reflect the order we write the registers to the DMA device. The txd {csrc,cdst,clli,cctl} values are duplicates of the lli[0] values, so there's no point duplicating these either. Program the DMAC registers directly from the lli[0] values. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 57 ++++++++++++++++------------------------------ include/linux/amba/pl08x.h | 13 ----------- 2 files changed, 19 insertions(+), 51 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index c025a4b4bae4..a1a18bde6b7f 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -193,33 +193,25 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, { struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_phy_chan *phychan = plchan->phychan; - u32 val; + struct pl08x_lli *lli = &txd->llis_va[0]; + u32 val, ccfg; plchan->at = txd; - /* Copy the basic control register calculated at transfer config */ - phychan->csrc = txd->csrc; - phychan->cdst = txd->cdst; - phychan->clli = txd->clli; - phychan->cctl = txd->cctl; - /* Assign the signal to the proper control registers */ - phychan->ccfg = plchan->cd->ccfg; - phychan->ccfg &= ~PL080_CONFIG_SRC_SEL_MASK; - phychan->ccfg &= ~PL080_CONFIG_DST_SEL_MASK; + ccfg = plchan->cd->ccfg; + ccfg &= ~(PL080_CONFIG_SRC_SEL_MASK | PL080_CONFIG_DST_SEL_MASK); + /* If it wasn't set from AMBA, ignore it */ if (txd->direction == DMA_TO_DEVICE) /* Select signal as destination */ - phychan->ccfg |= - (phychan->signal << PL080_CONFIG_DST_SEL_SHIFT); + ccfg |= phychan->signal << PL080_CONFIG_DST_SEL_SHIFT; else if (txd->direction == DMA_FROM_DEVICE) /* Select signal as source */ - phychan->ccfg |= - (phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT); - /* Always enable error interrupts */ - phychan->ccfg |= PL080_CONFIG_ERR_IRQ_MASK; - /* Always enable terminal interrupts */ - phychan->ccfg |= PL080_CONFIG_TC_IRQ_MASK; + ccfg |= phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT; + + /* Always enable error and terminal interrupts */ + ccfg |= PL080_CONFIG_ERR_IRQ_MASK | PL080_CONFIG_TC_IRQ_MASK; /* Wait for channel inactive */ while (pl08x_phy_channel_busy(phychan)) @@ -227,19 +219,15 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, dev_vdbg(&pl08x->adev->dev, "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, " - "cctl=0x%08x, clli=0x%08x, ccfg=0x%08x\n", - phychan->id, - phychan->csrc, - phychan->cdst, - phychan->cctl, - phychan->clli, - phychan->ccfg); - - writel(phychan->csrc, phychan->base + PL080_CH_SRC_ADDR); - writel(phychan->cdst, phychan->base + PL080_CH_DST_ADDR); - writel(phychan->clli, phychan->base + PL080_CH_LLI); - writel(phychan->cctl, phychan->base + PL080_CH_CONTROL); - writel(phychan->ccfg, phychan->base + PL080_CH_CONFIG); + "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n", + phychan->id, lli->src, lli->dst, lli->lli, lli->cctl, + ccfg); + + writel(lli->src, phychan->base + PL080_CH_SRC_ADDR); + writel(lli->dst, phychan->base + PL080_CH_DST_ADDR); + writel(lli->lli, phychan->base + PL080_CH_LLI); + writel(lli->cctl, phychan->base + PL080_CH_CONTROL); + writel(ccfg, phychan->base + PL080_CH_CONFIG); /* Enable the DMA channel */ /* Do not access config register until channel shows as disabled */ @@ -920,13 +908,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, */ llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN; - /* Now store the channel register values */ - txd->csrc = llis_va[0].src; - txd->cdst = llis_va[0].dst; - txd->clli = llis_va[0].lli; - txd->cctl = llis_va[0].cctl; - /* ccfg will be set at physical channel allocation time */ - #ifdef VERBOSE_DEBUG { int i; diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 2c834ed5f41f..29d974562df9 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -95,11 +95,6 @@ struct pl08x_phy_chan { spinlock_t lock; int signal; struct pl08x_dma_chan *serving; - u32 csrc; - u32 cdst; - u32 clli; - u32 cctl; - u32 ccfg; }; /** @@ -118,14 +113,6 @@ struct pl08x_txd { void *llis_va; struct pl08x_channel_data *cd; bool active; - /* - * Settings to be put into the physical channel when we - * trigger this txd - */ - u32 csrc; - u32 cdst; - u32 clli; - u32 cctl; }; /** -- cgit v1.2.3 From 4983a04fd2562986360b646b378f267308bc22c0 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:39:33 +0000 Subject: ARM: PL08x: move ccfg into txd structure The ccfg register is used to configure the channel parameters - the type and direction of transfer, the flow control signal and IRQ mask enables. The type and direction of transfer is known in the relevent prep_* function where a txd is created. The IRQ mask enables are always set, and the flow control signals are always set when we start processing a txd according to phychan->signal. If we store the ccfg value in the txd structure, we can avoid modifying platform data - and even having it in platform data at all. So, remove it from platform data too. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 28 ++++++++++++---------------- include/linux/amba/pl08x.h | 6 +++++- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index a1a18bde6b7f..75f9e2d4b032 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -194,15 +194,11 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_phy_chan *phychan = plchan->phychan; struct pl08x_lli *lli = &txd->llis_va[0]; - u32 val, ccfg; + u32 val, ccfg = txd->ccfg; plchan->at = txd; - /* Assign the signal to the proper control registers */ - ccfg = plchan->cd->ccfg; - ccfg &= ~(PL080_CONFIG_SRC_SEL_MASK | PL080_CONFIG_DST_SEL_MASK); - - /* If it wasn't set from AMBA, ignore it */ + /* Assign the flow control signal to this channel */ if (txd->direction == DMA_TO_DEVICE) /* Select signal as destination */ ccfg |= phychan->signal << PL080_CONFIG_DST_SEL_SHIFT; @@ -210,9 +206,6 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, /* Select signal as source */ ccfg |= phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT; - /* Always enable error and terminal interrupts */ - ccfg |= PL080_CONFIG_ERR_IRQ_MASK | PL080_CONFIG_TC_IRQ_MASK; - /* Wait for channel inactive */ while (pl08x_phy_channel_busy(phychan)) cpu_relax(); @@ -1161,8 +1154,6 @@ static void dma_set_runtime_config(struct dma_chan *chan, enum dma_slave_buswidth addr_width; u32 maxburst; u32 cctl = 0; - /* Mask out all except src and dst channel */ - u32 ccfg = cd->ccfg & 0x000003DEU; int i; /* Transfer direction */ @@ -1170,13 +1161,11 @@ static void dma_set_runtime_config(struct dma_chan *chan, if (config->direction == DMA_TO_DEVICE) { plchan->runtime_addr = config->dst_addr; cctl |= PL080_CONTROL_SRC_INCR; - ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; } else if (config->direction == DMA_FROM_DEVICE) { plchan->runtime_addr = config->src_addr; cctl |= PL080_CONTROL_DST_INCR; - ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; addr_width = config->src_addr_width; maxburst = config->src_maxburst; } else { @@ -1226,16 +1215,15 @@ static void dma_set_runtime_config(struct dma_chan *chan, /* Modify the default channel data to fit PrimeCell request */ cd->cctl = cctl; - cd->ccfg = ccfg; dev_dbg(&pl08x->adev->dev, "configured channel %s (%s) for %s, data width %d, " - "maxburst %d words, LE, CCTL=0x%08x, CCFG=0x%08x\n", + "maxburst %d words, LE, CCTL=0x%08x\n", dma_chan_name(chan), plchan->name, (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", addr_width, maxburst, - cctl, ccfg); + cctl); } /* @@ -1340,6 +1328,10 @@ static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan) dma_async_tx_descriptor_init(&txd->tx, &plchan->chan); txd->tx.tx_submit = pl08x_tx_submit; INIT_LIST_HEAD(&txd->node); + + /* Always enable error and terminal interrupts */ + txd->ccfg = PL080_CONFIG_ERR_IRQ_MASK | + PL080_CONFIG_TC_IRQ_MASK; } return txd; } @@ -1369,6 +1361,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( /* Set platform data for m2m */ txd->cd = &pl08x->pd->memcpy_channel; + txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; + /* Both to be incremented or the code will break */ txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; txd->len = len; @@ -1424,12 +1418,14 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( */ txd->direction = direction; if (direction == DMA_TO_DEVICE) { + txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->srcbus.addr = sgl->dma_address; if (plchan->runtime_addr) txd->dstbus.addr = plchan->runtime_addr; else txd->dstbus.addr = plchan->cd->addr; } else if (direction == DMA_FROM_DEVICE) { + txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; if (plchan->runtime_addr) txd->srcbus.addr = plchan->runtime_addr; else diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 29d974562df9..8e74cb1845dd 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -58,7 +58,6 @@ struct pl08x_channel_data { int max_signal; u32 muxval; u32 cctl; - u32 ccfg; dma_addr_t addr; bool circular_buffer; bool single; @@ -113,6 +112,11 @@ struct pl08x_txd { void *llis_va; struct pl08x_channel_data *cd; bool active; + /* + * Settings to be put into the physical channel when we + * trigger this txd. Other registers are in llis_va[0]. + */ + u32 ccfg; }; /** -- cgit v1.2.3 From 70b5ed6b6d72cd8b1a3d4b7b878a0dd132bec7ba Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:40:13 +0000 Subject: ARM: PL08x: move default cctl into txd structure Rather than modifying platform data while preparing a transfer, copy the cctl value into the txd structure and modify the value there. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 21 ++++++--------------- include/linux/amba/pl08x.h | 3 ++- 2 files changed, 8 insertions(+), 16 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index f0a29885cb83..6d224d41be2d 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -577,7 +577,6 @@ static inline size_t pl08x_pre_boundary(u32 addr, size_t len) static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { - struct pl08x_channel_data *cd = txd->cd; struct pl08x_bus_data *mbus, *sbus; size_t remainder; int num_llis = 0; @@ -595,17 +594,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, pl08x->pool_ctr++; - /* - * Initialize bus values for this transfer - * from the passed optimal values - */ - if (!cd) { - dev_err(&pl08x->adev->dev, "%s no channel data\n", __func__); - return 0; - } - - /* Get the default CCTL from the platform data */ - cctl = cd->cctl; + /* Get the default CCTL */ + cctl = txd->cctl; /* * On the PL080 we have two bus masters and we @@ -1358,11 +1348,11 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( txd->dstbus.addr = dest; /* Set platform data for m2m */ - txd->cd = &pl08x->pd->memcpy_channel; txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; + txd->cctl = pl08x->pd->memcpy_channel.cctl; /* Both to be incremented or the code will break */ - txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; + txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; txd->len = len; ret = pl08x_prep_channel_resources(plchan, txd); @@ -1415,6 +1405,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( * channel target address dynamically at runtime. */ txd->direction = direction; + txd->cctl = plchan->cd->cctl; + if (direction == DMA_TO_DEVICE) { txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->srcbus.addr = sgl->dma_address; @@ -1434,7 +1426,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( "%s direction unsupported\n", __func__); return NULL; } - txd->cd = plchan->cd; txd->len = sgl->length; ret = pl08x_prep_channel_resources(plchan, txd); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 8e74cb1845dd..8d9083067d3d 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -110,8 +110,9 @@ struct pl08x_txd { size_t len; dma_addr_t llis_bus; void *llis_va; - struct pl08x_channel_data *cd; bool active; + /* Default cctl value for LLIs */ + u32 cctl; /* * Settings to be put into the physical channel when we * trigger this txd. Other registers are in llis_va[0]. -- cgit v1.2.3 From 30749cb4a40f02a199640011e5ab5c5f60b8482e Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:41:13 +0000 Subject: ARM: PL08x: allow AHB master port selection to be configured Platforms need to be able to control which AHB master interface is used, as each AHB master interface may be asymetric. Allow the interfaces used for fetching LLIs, memory, and each peripheral to be configured individually. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 77 ++++++++++++++++++++++++++-------------------- include/linux/amba/pl08x.h | 15 +++++++-- 2 files changed, 56 insertions(+), 36 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 4ee0ab19b1b6..986c12775b0b 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -126,6 +126,8 @@ struct pl08x_lli { * @phy_chans: array of data for the physical channels * @pool: a pool for the LLI descriptors * @pool_ctr: counter of LLIs in the pool + * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI fetches + * @mem_buses: set to indicate memory transfers on AHB2. * @lock: a spinlock for this struct */ struct pl08x_driver_data { @@ -138,6 +140,8 @@ struct pl08x_driver_data { struct pl08x_phy_chan *phy_chans; struct dma_pool *pool; int pool_ctr; + u8 lli_buses; + u8 mem_buses; spinlock_t lock; }; @@ -526,20 +530,12 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); - llis_va[num_llis].cctl = cctl; - llis_va[num_llis].src = txd->srcbus.addr; - llis_va[num_llis].dst = txd->dstbus.addr; - - /* - * On versions with dual masters, you can optionally AND on - * PL080_LLI_LM_AHB2 to the LLI to tell the hardware to read - * in new LLIs with that controller, but we always try to - * choose AHB1 to point into memory. The idea is to have AHB2 - * fixed on the peripheral and AHB1 messing around in the - * memory. So we don't manipulate this bit currently. - */ - + llis_va[num_llis].cctl = cctl; + llis_va[num_llis].src = txd->srcbus.addr; + llis_va[num_llis].dst = txd->dstbus.addr; llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); + if (pl08x->lli_buses & PL08X_AHB2) + llis_va[num_llis].lli |= PL080_LLI_LM_AHB2; if (cctl & PL080_CONTROL_SRC_INCR) txd->srcbus.addr += len; @@ -639,13 +635,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus, &mbus, &sbus, cctl); - - /* - * The lowest bit of the LLI register - * is also used to indicate which master to - * use for reading the LLIs. - */ - if (txd->len < mbus->buswidth) { /* * Less than a bus width available @@ -1282,6 +1271,23 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, return 0; } +/* + * Given the source and destination available bus masks, select which + * will be routed to each port. We try to have source and destination + * on separate ports, but always respect the allowable settings. + */ +static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst) +{ + u32 cctl = 0; + + if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1))) + cctl |= PL080_CONTROL_DST_AHB2; + if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2))) + cctl |= PL080_CONTROL_SRC_AHB2; + + return cctl; +} + static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan) { struct pl08x_txd *txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); @@ -1330,15 +1336,9 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( /* Both to be incremented or the code will break */ txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; - /* - * On the PL080 we have two bus masters and we should select one for - * source and one for destination. We try to use AHB2 for the bus - * which does not increment (typically the peripheral) else we just - * choose something. - */ if (pl08x->vd->dualmaster) - /* Source increments, use AHB2 for destination */ - txd->cctl |= PL080_CONTROL_DST_AHB2; + txd->cctl |= pl08x_select_bus(pl08x, + pl08x->mem_buses, pl08x->mem_buses); ret = pl08x_prep_channel_resources(plchan, txd); if (ret) @@ -1359,6 +1359,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; + u8 src_buses, dst_buses; int ret; /* @@ -1403,31 +1404,31 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( if (direction == DMA_TO_DEVICE) { txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_SRC_INCR; - if (pl08x->vd->dualmaster) - /* Source increments, use AHB2 for destination */ - txd->cctl |= PL080_CONTROL_DST_AHB2; txd->srcbus.addr = sgl->dma_address; if (plchan->runtime_addr) txd->dstbus.addr = plchan->runtime_addr; else txd->dstbus.addr = plchan->cd->addr; + src_buses = pl08x->mem_buses; + dst_buses = plchan->cd->periph_buses; } else if (direction == DMA_FROM_DEVICE) { txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_DST_INCR; - if (pl08x->vd->dualmaster) - /* Destination increments, use AHB2 for source */ - txd->cctl |= PL080_CONTROL_SRC_AHB2; if (plchan->runtime_addr) txd->srcbus.addr = plchan->runtime_addr; else txd->srcbus.addr = plchan->cd->addr; txd->dstbus.addr = sgl->dma_address; + src_buses = plchan->cd->periph_buses; + dst_buses = pl08x->mem_buses; } else { dev_err(&pl08x->adev->dev, "%s direction unsupported\n", __func__); return NULL; } + txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses); + ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; @@ -1879,6 +1880,14 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) pl08x->adev = adev; pl08x->vd = vd; + /* By default, AHB1 only. If dualmaster, from platform */ + pl08x->lli_buses = PL08X_AHB1; + pl08x->mem_buses = PL08X_AHB1; + if (pl08x->vd->dualmaster) { + pl08x->lli_buses = pl08x->pd->lli_buses; + pl08x->mem_buses = pl08x->pd->mem_buses; + } + /* A DMA memory pool for LLIs, align on 1-byte boundary */ pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev, PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 8d9083067d3d..f858651027fd 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -25,6 +25,12 @@ struct pl08x_lli; struct pl08x_driver_data; +/* Bitmasks for selecting AHB ports for DMA transfers */ +enum { + PL08X_AHB1 = (1 << 0), + PL08X_AHB2 = (1 << 1) +}; + /** * struct pl08x_channel_data - data structure to pass info between * platform and PL08x driver regarding channel configuration @@ -51,6 +57,8 @@ struct pl08x_driver_data; * round round round) * @single: the device connected to this channel will request single * DMA transfers, not bursts. (Bursts are default.) + * @periph_buses: the device connected to this channel is accessible via + * these buses (use PL08X_AHB1 | PL08X_AHB2). */ struct pl08x_channel_data { char *bus_id; @@ -61,6 +69,7 @@ struct pl08x_channel_data { dma_addr_t addr; bool circular_buffer; bool single; + u8 periph_buses; }; /** @@ -193,8 +202,8 @@ struct pl08x_dma_chan { * less than zero, else it returns the allocated signal number * @put_signal: indicate to the platform that this physical signal is not * running any DMA transfer and multiplexing can be recycled - * @bus_bit_lli: Bit[0] of the address indicated which AHB bus master the - * LLI addresses are on 0/1 Master 1/2. + * @lli_buses: buses which LLIs can be fetched from: PL08X_AHB1 | PL08X_AHB2 + * @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2 */ struct pl08x_platform_data { struct pl08x_channel_data *slave_channels; @@ -202,6 +211,8 @@ struct pl08x_platform_data { struct pl08x_channel_data memcpy_channel; int (*get_signal)(struct pl08x_dma_chan *); void (*put_signal)(struct pl08x_dma_chan *); + u8 lli_buses; + u8 mem_buses; }; #ifdef CONFIG_AMBA_PL08X -- cgit v1.2.3 From d7244e9a27a3da27d62aabf560ee828d7991493e Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:43:35 +0000 Subject: ARM: PL08x: shrink srcbus/dstbus in txd structure We only need to store the dma address. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 20 ++++++++++---------- include/linux/amba/pl08x.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 39970c5038d6..8d8d33ce5684 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -595,8 +595,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, bd.txd = txd; bd.pl08x = pl08x; - bd.srcbus.addr = txd->srcbus.addr; - bd.dstbus.addr = txd->dstbus.addr; + bd.srcbus.addr = txd->src_addr; + bd.dstbus.addr = txd->dst_addr; /* Find maximum width of the source bus */ bd.srcbus.maxwidth = @@ -1313,8 +1313,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( } txd->direction = DMA_NONE; - txd->srcbus.addr = src; - txd->dstbus.addr = dest; + txd->src_addr = src; + txd->dst_addr = dest; txd->len = len; /* Set platform data for m2m */ @@ -1393,21 +1393,21 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( if (direction == DMA_TO_DEVICE) { txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_SRC_INCR; - txd->srcbus.addr = sgl->dma_address; + txd->src_addr = sgl->dma_address; if (plchan->runtime_addr) - txd->dstbus.addr = plchan->runtime_addr; + txd->dst_addr = plchan->runtime_addr; else - txd->dstbus.addr = plchan->cd->addr; + txd->dst_addr = plchan->cd->addr; src_buses = pl08x->mem_buses; dst_buses = plchan->cd->periph_buses; } else if (direction == DMA_FROM_DEVICE) { txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_DST_INCR; if (plchan->runtime_addr) - txd->srcbus.addr = plchan->runtime_addr; + txd->src_addr = plchan->runtime_addr; else - txd->srcbus.addr = plchan->cd->addr; - txd->dstbus.addr = sgl->dma_address; + txd->src_addr = plchan->cd->addr; + txd->dst_addr = sgl->dma_address; src_buses = plchan->cd->periph_buses; dst_buses = pl08x->mem_buses; } else { diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index f858651027fd..4e9e71860e1c 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -114,8 +114,8 @@ struct pl08x_txd { struct dma_async_tx_descriptor tx; struct list_head node; enum dma_data_direction direction; - struct pl08x_bus_data srcbus; - struct pl08x_bus_data dstbus; + dma_addr_t src_addr; + dma_addr_t dst_addr; size_t len; dma_addr_t llis_bus; void *llis_va; -- cgit v1.2.3 From 15c17232fbd1f7687c740c3c26f9e7f337bd9e36 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:44:36 +0000 Subject: ARM: PL08x: rename 'desc_list' as 'pend_list' This 'desc_list' is actually a list of pending descriptors, so name it after its function (pending list) rather than what it contains (descriptors). Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 20 ++++++++++---------- include/linux/amba/pl08x.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index fb469dedcdf3..433b9e747f75 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -348,9 +348,9 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) } /* Sum up all queued transactions */ - if (!list_empty(&plchan->desc_list)) { + if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *txdi; - list_for_each_entry(txdi, &plchan->desc_list, node) { + list_for_each_entry(txdi, &plchan->pend_list, node) { bytes += txdi->len; } } @@ -880,9 +880,9 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, struct pl08x_txd *txdi = NULL; struct pl08x_txd *next; - if (!list_empty(&plchan->desc_list)) { + if (!list_empty(&plchan->pend_list)) { list_for_each_entry_safe(txdi, - next, &plchan->desc_list, node) { + next, &plchan->pend_list, node) { list_del(&txdi->node); pl08x_free_txd(pl08x, txdi); } @@ -1183,10 +1183,10 @@ static void pl08x_issue_pending(struct dma_chan *chan) } /* Take the first element in the queue and execute it */ - if (!list_empty(&plchan->desc_list)) { + if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *next; - next = list_first_entry(&plchan->desc_list, + next = list_first_entry(&plchan->pend_list, struct pl08x_txd, node); list_del(&next->node); @@ -1213,7 +1213,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, spin_lock_irqsave(&plchan->lock, plchan->lockflags); - list_add_tail(&txd->node, &plchan->desc_list); + list_add_tail(&txd->node, &plchan->pend_list); /* * See if we already have a physical channel allocated, @@ -1571,10 +1571,10 @@ static void pl08x_tasklet(unsigned long data) * If a new descriptor is queued, set it up * plchan->at is NULL here */ - if (!list_empty(&plchan->desc_list)) { + if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *next; - next = list_first_entry(&plchan->desc_list, + next = list_first_entry(&plchan->pend_list, struct pl08x_txd, node); list_del(&next->node); @@ -1736,7 +1736,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, chan->lc = 0; spin_lock_init(&chan->lock); - INIT_LIST_HEAD(&chan->desc_list); + INIT_LIST_HEAD(&chan->pend_list); tasklet_init(&chan->tasklet, pl08x_tasklet, (unsigned long) chan); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 4e9e71860e1c..08a9024e2d2f 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -158,7 +158,7 @@ enum pl08x_dma_chan_state { * @runtime_direction: current direction of this channel according to * runtime config * @lc: last completed transaction on this channel - * @desc_list: queued transactions pending on this channel + * @pend_list: queued transactions pending on this channel * @at: active transaction on this channel * @lockflags: sometimes we let a lock last between two function calls, * especially prep/submit, and then we need to store the IRQ flags @@ -179,7 +179,7 @@ struct pl08x_dma_chan { dma_addr_t runtime_addr; enum dma_data_direction runtime_direction; dma_cookie_t lc; - struct list_head desc_list; + struct list_head pend_list; struct pl08x_txd *at; unsigned long lockflags; spinlock_t lock; -- cgit v1.2.3 From 8087aacda040bdbf84940712d132ce80c30b9d5d Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:45:17 +0000 Subject: ARM: PL08x: introduce 'phychan_hold' to hold on to physical channels Introduce 'phychan_hold' to hold on to physical DMA channels while we're preparing a new descriptor for it. This will be incremented when we allocate a physical channel and set the MUX registers during the preparation of the TXD, and will only be decremented when the TXD is submitted. This prevents the physical channel being given up before the new TXD is placed on the queue. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 11 +++++++++++ include/linux/amba/pl08x.h | 3 +++ 2 files changed, 14 insertions(+) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 650e2bbc7aad..bf6f7d02c9f6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -959,6 +959,7 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, ch->signal, plchan->name); + plchan->phychan_hold++; plchan->phychan = ch; return 0; @@ -998,6 +999,8 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) /* Do this memcpy whenever there is a channel ready */ plchan->state = PL08X_CHAN_WAITING; plchan->waiting = txd; + } else { + plchan->phychan_hold--; } /* This unlock follows the lock in the prep() function */ @@ -1585,6 +1588,7 @@ static void pl08x_tasklet(unsigned long data) */ plchan->lc = txd->tx.cookie; } + /* * If a new descriptor is queued, set it up * plchan->at is NULL here @@ -1598,6 +1602,12 @@ static void pl08x_tasklet(unsigned long data) list_del(&next->node); pl08x_start_txd(plchan, next); + } else if (plchan->phychan_hold) { + /* + * This channel is still in use - we have a new txd being + * prepared and will soon be queued. Don't give up the + * physical channel. + */ } else { struct pl08x_dma_chan *waiting = NULL; @@ -1625,6 +1635,7 @@ static void pl08x_tasklet(unsigned long data) ret = prep_phy_channel(waiting, waiting->waiting); BUG_ON(ret); + waiting->phychan_hold--; waiting->state = PL08X_CHAN_RUNNING; waiting->waiting = NULL; pl08x_issue_pending(&waiting->chan); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 08a9024e2d2f..95b76ea1829f 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -151,6 +151,8 @@ enum pl08x_dma_chan_state { * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel * @chan: wrappped abstract channel * @phychan: the physical channel utilized by this channel, if there is one + * @phychan_hold: if non-zero, hold on to the physical channel even if we + * have no pending entries * @tasklet: tasklet scheduled by the IRQ to handle actual work etc * @name: name of channel * @cd: channel platform data @@ -173,6 +175,7 @@ enum pl08x_dma_chan_state { struct pl08x_dma_chan { struct dma_chan chan; struct pl08x_phy_chan *phychan; + int phychan_hold; struct tasklet_struct tasklet; char *name; struct pl08x_channel_data *cd; -- cgit v1.2.3 From c370e594efe2993620d24d41a78f325102e99d1c Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:45:37 +0000 Subject: ARM: PL08x: fix locking between prepare function and submit function The PL08x driver holds on to the channel lock with interrupts disabled between the prepare and the subsequent submit API functions. This means that the locking state when the prepare function returns is dependent on whether it suceeeds or not. It did this to ensure that the physical channel wasn't released, and as it used to add the descriptor onto the pending list at prepare time rather than submit time. Now that we have reorganized the code to remove those reasons, we can now safely release the spinlock at the end of preparation and reacquire it in our submit function. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 28 +++++++++------------------- include/linux/amba/pl08x.h | 4 ---- 2 files changed, 9 insertions(+), 23 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index bf6f7d02c9f6..1c9f712520d6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -981,6 +981,9 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) { struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan); struct pl08x_txd *txd = to_pl08x_txd(tx); + unsigned long flags; + + spin_lock_irqsave(&plchan->lock, flags); plchan->chan.cookie += 1; if (plchan->chan.cookie < 0) @@ -1003,8 +1006,7 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) plchan->phychan_hold--; } - /* This unlock follows the lock in the prep() function */ - spin_unlock_irqrestore(&plchan->lock, plchan->lockflags); + spin_unlock_irqrestore(&plchan->lock, flags); return tx->cookie; } @@ -1225,9 +1227,9 @@ static void pl08x_issue_pending(struct dma_chan *chan) static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, struct pl08x_txd *txd) { - int num_llis; struct pl08x_driver_data *pl08x = plchan->host; - int ret; + unsigned long flags; + int num_llis, ret; num_llis = pl08x_fill_llis_for_desc(pl08x, txd); if (!num_llis) { @@ -1235,7 +1237,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, return -EINVAL; } - spin_lock_irqsave(&plchan->lock, plchan->lockflags); + spin_lock_irqsave(&plchan->lock, flags); /* * See if we already have a physical channel allocated, @@ -1258,7 +1260,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, if (plchan->slave) { pl08x_free_txd_list(pl08x, plchan); pl08x_free_txd(pl08x, txd); - spin_unlock_irqrestore(&plchan->lock, plchan->lockflags); + spin_unlock_irqrestore(&plchan->lock, flags); return -EBUSY; } } else @@ -1272,11 +1274,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, if (plchan->state == PL08X_CHAN_IDLE) plchan->state = PL08X_CHAN_PAUSED; - /* - * Notice that we leave plchan->lock locked on purpose: - * it will be unlocked in the subsequent tx_submit() - * call. This is a consequence of the current API. - */ + spin_unlock_irqrestore(&plchan->lock, flags); return 0; } @@ -1355,10 +1353,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; - /* - * NB: the channel lock is held at this point so tx_submit() - * must be called in direct succession. - */ return &txd->tx; } @@ -1444,10 +1438,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; - /* - * NB: the channel lock is held at this point so tx_submit() - * must be called in direct succession. - */ return &txd->tx; } diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 95b76ea1829f..933b4ed12be5 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -162,9 +162,6 @@ enum pl08x_dma_chan_state { * @lc: last completed transaction on this channel * @pend_list: queued transactions pending on this channel * @at: active transaction on this channel - * @lockflags: sometimes we let a lock last between two function calls, - * especially prep/submit, and then we need to store the IRQ flags - * in the channel state, here * @lock: a lock for this channel data * @host: a pointer to the host (internal use) * @state: whether the channel is idle, paused, running etc @@ -184,7 +181,6 @@ struct pl08x_dma_chan { dma_cookie_t lc; struct list_head pend_list; struct pl08x_txd *at; - unsigned long lockflags; spinlock_t lock; struct pl08x_driver_data *host; enum pl08x_dma_chan_state state; -- cgit v1.2.3 From 96a608a4bfd8468c21881b3f92024923886eb015 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 14 Jan 2011 17:51:11 -0800 Subject: ARM: PL08x: fix a warning drivers/dma/amba-pl08x.c: In function 'pl08x_start_txd': drivers/dma/amba-pl08x.c:205: warning: dereferencing 'void *' pointer We never dereference llis_va aside from assigning it to a struct pl08x_lli pointer or calculating the address of array element 0. Signed-off-by: Dan Williams --- include/linux/amba/pl08x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux/amba') diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 933b4ed12be5..5b87b6aac3f8 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -118,7 +118,7 @@ struct pl08x_txd { dma_addr_t dst_addr; size_t len; dma_addr_t llis_bus; - void *llis_va; + struct pl08x_lli *llis_va; bool active; /* Default cctl value for LLIs */ u32 cctl; -- cgit v1.2.3 From 94ae85220a07d357d4937086c490854f63344de4 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 16 Jan 2011 20:18:05 +0000 Subject: ARM: PL08x: cleanup comments Cleanup the formatting of comments, remove some which don't make sense anymore. Signed-off-by: Russell King [fix conflict with 96a608a4] Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 146 ++++++++++++++++----------------------------- include/linux/amba/pl08x.h | 43 +++++++------ 2 files changed, 72 insertions(+), 117 deletions(-) (limited to 'include/linux/amba') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index bebc678ed4fc..297f48b0cba9 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -19,14 +19,14 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The full GNU General Public License is in this distribution in the - * file called COPYING. + * The full GNU General Public License is in this distribution in the file + * called COPYING. * * Documentation: ARM DDI 0196G == PL080 - * Documentation: ARM DDI 0218E == PL081 + * Documentation: ARM DDI 0218E == PL081 * - * PL080 & PL081 both have 16 sets of DMA signals that can be routed to - * any channel. + * PL080 & PL081 both have 16 sets of DMA signals that can be routed to any + * channel. * * The PL080 has 8 channels available for simultaneous use, and the PL081 * has only two channels. So on these DMA controllers the number of channels @@ -91,11 +91,9 @@ #define DRIVER_NAME "pl08xdmac" /** - * struct vendor_data - vendor-specific config parameters - * for PL08x derivatives + * struct vendor_data - vendor-specific config parameters for PL08x derivatives * @channels: the number of channels available in this variant - * @dualmaster: whether this version supports dual AHB masters - * or not. + * @dualmaster: whether this version supports dual AHB masters or not. */ struct vendor_data { u8 channels; @@ -241,10 +239,8 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, * * Disabling individual channels could lose data. * - * Disable the peripheral DMA after disabling the DMAC - * in order to allow the DMAC FIFO to drain, and - * hence allow the channel to show inactive - * + * Disable the peripheral DMA after disabling the DMAC in order to allow + * the DMAC FIFO to drain, and hence allow the channel to show inactive */ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch) { @@ -367,6 +363,10 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) /* * Allocate a physical channel for a virtual channel + * + * Try to locate a physical channel to be used for this transfer. If all + * are taken return NULL and the requester will have to cope by using + * some fallback PIO mode or retrying later. */ static struct pl08x_phy_chan * pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, @@ -376,12 +376,6 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, unsigned long flags; int i; - /* - * Try to locate a physical channel to be used for - * this transfer. If all are taken return NULL and - * the requester will have to cope by using some fallback - * PIO mode or retrying later. - */ for (i = 0; i < pl08x->vd->channels; i++) { ch = &pl08x->phy_chans[i]; @@ -495,9 +489,9 @@ struct pl08x_lli_build_data { }; /* - * Autoselect a master bus to use for the transfer - * this prefers the destination bus if both available - * if fixed address on one bus the other will be chosen + * Autoselect a master bus to use for the transfer this prefers the + * destination bus if both available if fixed address on one bus the + * other will be chosen */ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl) @@ -530,8 +524,7 @@ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, } /* - * Fills in one LLI for a certain transfer descriptor - * and advance the counter + * Fills in one LLI for a certain transfer descriptor and advance the counter */ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, int num_llis, int len, u32 cctl) @@ -640,15 +633,11 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * Choose bus to align to * - prefers destination bus if both available * - if fixed address on one bus chooses other - * - modifies cctl to choose an appropriate master */ pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); if (txd->len < mbus->buswidth) { - /* - * Less than a bus width available - * - send as single bytes - */ + /* Less than a bus width available - send as single bytes */ while (bd.remainder) { dev_vdbg(&pl08x->adev->dev, "%s single byte LLIs for a transfer of " @@ -659,10 +648,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, total_bytes++; } } else { - /* - * Make one byte LLIs until master bus is aligned - * - slave will then be aligned also - */ + /* Make one byte LLIs until master bus is aligned */ while ((mbus->addr) % (mbus->buswidth)) { dev_vdbg(&pl08x->adev->dev, "%s adjustment lli for less than bus width " @@ -674,7 +660,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } /* - * Master now aligned + * Master now aligned * - if slave is not then we must set its width down */ if (sbus->addr % sbus->buswidth) { @@ -732,10 +718,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (lli_len == target_len) { /* - * Can send what we wanted - */ - /* - * Maintain alignment + * Can send what we wanted. + * Maintain alignment */ lli_len = (lli_len/mbus->buswidth) * mbus->buswidth; @@ -743,17 +727,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } else { /* * So now we know how many bytes to transfer - * to get to the nearest boundary - * The next LLI will past the boundary - * - however we may be working to a boundary - * on the slave bus - * We need to ensure the master stays aligned + * to get to the nearest boundary. The next + * LLI will past the boundary. However, we + * may be working to a boundary on the slave + * bus. We need to ensure the master stays + * aligned, and that we are working in + * multiples of the bus widths. */ odd_bytes = lli_len % mbus->buswidth; - /* - * - and that we are working in multiples - * of the bus widths - */ lli_len -= odd_bytes; } @@ -793,8 +774,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (odd_bytes) { /* - * Creep past the boundary, - * maintaining master alignment + * Creep past the boundary, maintaining + * master alignment */ int j; for (j = 0; (j < mbus->buswidth) @@ -837,13 +818,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } llis_va = txd->llis_va; - /* - * The final LLI terminates the LLI. - */ + /* The final LLI terminates the LLI. */ llis_va[num_llis - 1].lli = 0; - /* - * The final LLI element shall also fire an interrupt - */ + /* The final LLI element shall also fire an interrupt. */ llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN; #ifdef VERBOSE_DEBUG @@ -891,7 +868,6 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, list_del(&txdi->node); pl08x_free_txd(pl08x, txdi); } - } } @@ -1020,10 +996,9 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt( } /* - * Code accessing dma_async_is_complete() in a tight loop - * may give problems - could schedule where indicated. - * If slaves are relying on interrupts to signal completion this - * function must not be called with interrupts disabled + * Code accessing dma_async_is_complete() in a tight loop may give problems. + * If slaves are relying on interrupts to signal completion this function + * must not be called with interrupts disabled. */ static enum dma_status pl08x_dma_tx_status(struct dma_chan *chan, @@ -1045,10 +1020,6 @@ pl08x_dma_tx_status(struct dma_chan *chan, return ret; } - /* - * schedule(); could be inserted here - */ - /* * This cookie not complete yet */ @@ -1273,11 +1244,10 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, } } else /* - * Else we're all set, paused and ready to roll, - * status will switch to PL08X_CHAN_RUNNING when - * we call issue_pending(). If there is something - * running on the channel already we don't change - * its state. + * Else we're all set, paused and ready to roll, status + * will switch to PL08X_CHAN_RUNNING when we call + * issue_pending(). If there is something running on the + * channel already we don't change its state. */ if (plchan->state == PL08X_CHAN_IDLE) plchan->state = PL08X_CHAN_PAUSED; @@ -1528,10 +1498,9 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) /* * Just check that the device is there and active - * TODO: turn this bit on/off depending on the number of - * physical channels actually used, if it is zero... well - * shut it off. That will save some power. Cut the clock - * at the same time. + * TODO: turn this bit on/off depending on the number of physical channels + * actually used, if it is zero... well shut it off. That will save some + * power. Cut the clock at the same time. */ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) { @@ -1579,16 +1548,11 @@ static void pl08x_tasklet(unsigned long data) plchan->at = NULL; if (txd) { - /* - * Update last completed - */ + /* Update last completed */ plchan->lc = txd->tx.cookie; } - /* - * If a new descriptor is queued, set it up - * plchan->at is NULL here - */ + /* If a new descriptor is queued, set it up plchan->at is NULL here */ if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *next; @@ -1615,11 +1579,10 @@ static void pl08x_tasklet(unsigned long data) plchan->state = PL08X_CHAN_IDLE; /* - * And NOW before anyone else can grab that free:d - * up physical channel, see if there is some memcpy - * pending that seriously needs to start because of - * being stacked up while we were choking the - * physical channels with data. + * And NOW before anyone else can grab that free:d up + * physical channel, see if there is some memcpy pending + * that seriously needs to start because of being stacked + * up while we were choking the physical channels with data. */ list_for_each_entry(waiting, &pl08x->memcpy.channels, chan.device_node) { @@ -1670,9 +1633,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev) val = readl(pl08x->base + PL080_ERR_STATUS); if (val) { - /* - * An error interrupt (on one or more channels) - */ + /* An error interrupt (on one or more channels) */ dev_err(&pl08x->adev->dev, "%s error interrupt, register value 0x%08x\n", __func__, val); @@ -1696,9 +1657,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev) mask |= (1 << i); } } - /* - * Clear only the terminal interrupts on channels we processed - */ + /* Clear only the terminal interrupts on channels we processed */ writel(mask, pl08x->base + PL080_TC_CLEAR); return mask ? IRQ_HANDLED : IRQ_NONE; @@ -1717,6 +1676,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, int i; INIT_LIST_HEAD(&dmadev->channels); + /* * Register as many many memcpy as we have physical channels, * we won't always be able to use all but the code will have @@ -1950,9 +1910,7 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) /* Turn on the PL08x */ pl08x_ensure_on(pl08x); - /* - * Attach the interrupt handler - */ + /* Attach the interrupt handler */ writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR); writel(0x000000FF, pl08x->base + PL080_TC_CLEAR); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 5b87b6aac3f8..3111385b8ca7 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -12,7 +12,6 @@ * * Please credit ARM.com * Documentation: ARM DDI 0196D - * */ #ifndef AMBA_PL08X_H @@ -55,8 +54,8 @@ enum { * @circular_buffer: whether the buffer passed in is circular and * shall simply be looped round round (like a record baby round * round round round) - * @single: the device connected to this channel will request single - * DMA transfers, not bursts. (Bursts are default.) + * @single: the device connected to this channel will request single DMA + * transfers, not bursts. (Bursts are default.) * @periph_buses: the device connected to this channel is accessible via * these buses (use PL08X_AHB1 | PL08X_AHB2). */ @@ -78,8 +77,7 @@ struct pl08x_channel_data { * @addr: current address * @maxwidth: the maximum width of a transfer on this bus * @buswidth: the width of this bus in bytes: 1, 2 or 4 - * @fill_bytes: bytes required to fill to the next bus memory - * boundary + * @fill_bytes: bytes required to fill to the next bus memory boundary */ struct pl08x_bus_data { dma_addr_t addr; @@ -92,10 +90,10 @@ struct pl08x_bus_data { * struct pl08x_phy_chan - holder for the physical channels * @id: physical index to this channel * @lock: a lock to use when altering an instance of this struct - * @signal: the physical signal (aka channel) serving this - * physical channel right now - * @serving: the virtual channel currently being served by this - * physical channel + * @signal: the physical signal (aka channel) serving this physical channel + * right now + * @serving: the virtual channel currently being served by this physical + * channel */ struct pl08x_phy_chan { unsigned int id; @@ -119,7 +117,6 @@ struct pl08x_txd { size_t len; dma_addr_t llis_bus; struct pl08x_lli *llis_va; - bool active; /* Default cctl value for LLIs */ u32 cctl; /* @@ -130,8 +127,8 @@ struct pl08x_txd { }; /** - * struct pl08x_dma_chan_state - holds the PL08x specific virtual - * channel states + * struct pl08x_dma_chan_state - holds the PL08x specific virtual channel + * states * @PL08X_CHAN_IDLE: the channel is idle * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport * channel and is running a transfer on it @@ -152,7 +149,7 @@ enum pl08x_dma_chan_state { * @chan: wrappped abstract channel * @phychan: the physical channel utilized by this channel, if there is one * @phychan_hold: if non-zero, hold on to the physical channel even if we - * have no pending entries + * have no pending entries * @tasklet: tasklet scheduled by the IRQ to handle actual work etc * @name: name of channel * @cd: channel platform data @@ -166,8 +163,8 @@ enum pl08x_dma_chan_state { * @host: a pointer to the host (internal use) * @state: whether the channel is idle, paused, running etc * @slave: whether this channel is a device (slave) or for memcpy - * @waiting: a TX descriptor on this channel which is waiting for - * a physical channel to become available + * @waiting: a TX descriptor on this channel which is waiting for a physical + * channel to become available */ struct pl08x_dma_chan { struct dma_chan chan; @@ -189,16 +186,16 @@ struct pl08x_dma_chan { }; /** - * struct pl08x_platform_data - the platform configuration for the - * PL08x PrimeCells. + * struct pl08x_platform_data - the platform configuration for the PL08x + * PrimeCells. * @slave_channels: the channels defined for the different devices on the * platform, all inclusive, including multiplexed channels. The available - * physical channels will be multiplexed around these signals as they - * are requested, just enumerate all possible channels. - * @get_signal: request a physical signal to be used for a DMA - * transfer immediately: if there is some multiplexing or similar blocking - * the use of the channel the transfer can be denied by returning - * less than zero, else it returns the allocated signal number + * physical channels will be multiplexed around these signals as they are + * requested, just enumerate all possible channels. + * @get_signal: request a physical signal to be used for a DMA transfer + * immediately: if there is some multiplexing or similar blocking the use + * of the channel the transfer can be denied by returning less than zero, + * else it returns the allocated signal number * @put_signal: indicate to the platform that this physical signal is not * running any DMA transfer and multiplexing can be recycled * @lli_buses: buses which LLIs can be fetched from: PL08X_AHB1 | PL08X_AHB2 -- cgit v1.2.3