From 585a9d0b43d109ad76c0e43eae0fbe5ec3196246 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:18 +0200 Subject: dmaengine: pl330: Use dma_transfer_direction instead of custom pl330_reqtype The pl330 driver has the custom pl330_reqtype enum which has the same possible settings as the generic dma_transfer_direction enum. Switching over to the generic enum internally makes it possible to directly initialize it from the transfer request direction. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 73fa9b7a10ab..3aff676af853 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -63,13 +63,6 @@ enum pl330_byteswap { SWAP_16, }; -enum pl330_reqtype { - MEMTOMEM, - MEMTODEV, - DEVTOMEM, - DEVTODEV, -}; - /* Register and Bit field Definitions */ #define DS 0x0 #define DS_ST_STOP 0x0 @@ -378,7 +371,7 @@ enum pl330_op_err { /* A request defining Scatter-Gather List ending with NULL xfer. */ struct pl330_req { - enum pl330_reqtype rqtype; + enum dma_transfer_direction rqtype; /* Index of peripheral for the xfer. */ unsigned peri:5; /* Unique token for this xfer, set by the client. */ @@ -1296,13 +1289,13 @@ static int _bursts(unsigned dry_run, u8 buf[], int off = 0; switch (pxs->r->rqtype) { - case MEMTODEV: + case DMA_MEM_TO_DEV: off += _ldst_memtodev(dry_run, &buf[off], pxs, cyc); break; - case DEVTOMEM: + case DMA_DEV_TO_MEM: off += _ldst_devtomem(dry_run, &buf[off], pxs, cyc); break; - case MEMTOMEM: + case DMA_MEM_TO_MEM: off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc); break; default: @@ -1543,7 +1536,7 @@ static int pl330_submit_req(void *ch_id, struct pl330_req *r) } /* If request for non-existing peripheral */ - if (r->rqtype != MEMTOMEM && r->peri >= pi->pcfg.num_peri) { + if (r->rqtype != DMA_MEM_TO_MEM && r->peri >= pi->pcfg.num_peri) { dev_info(thrd->dmac->pinfo->dev, "%s:%d Invalid peripheral(%u)!\n", __func__, __LINE__, r->peri); @@ -2698,14 +2691,12 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( case DMA_MEM_TO_DEV: desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 0; - desc->req.rqtype = MEMTODEV; src = dma_addr; dst = pch->fifo_addr; break; case DMA_DEV_TO_MEM: desc->rqcfg.src_inc = 0; desc->rqcfg.dst_inc = 1; - desc->req.rqtype = DEVTOMEM; src = pch->fifo_addr; dst = dma_addr; break; @@ -2713,6 +2704,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( break; } + desc->req.rqtype = direction; desc->rqcfg.brst_size = pch->burst_sz; desc->rqcfg.brst_len = 1; fill_px(&desc->px, dst, src, period_len); @@ -2754,7 +2746,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 1; - desc->req.rqtype = MEMTOMEM; + desc->req.rqtype = DMA_MEM_TO_MEM; /* Select max possible burst size */ burst = pi->pcfg.data_bus_width / 8; @@ -2838,19 +2830,18 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (direction == DMA_MEM_TO_DEV) { desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 0; - desc->req.rqtype = MEMTODEV; fill_px(&desc->px, addr, sg_dma_address(sg), sg_dma_len(sg)); } else { desc->rqcfg.src_inc = 0; desc->rqcfg.dst_inc = 1; - desc->req.rqtype = DEVTOMEM; fill_px(&desc->px, sg_dma_address(sg), addr, sg_dma_len(sg)); } desc->rqcfg.brst_size = pch->burst_sz; desc->rqcfg.brst_len = 1; + desc->req.rqtype = direction; } /* Return the last desc in the chain */ -- cgit v1.2.3 From f0564c7ecbc07a1290dabc8720f9dc03f22fa563 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:19 +0200 Subject: dmaengine: pl330: Remove duplicated cachecontrol enum The settings for destination and source cache control are exactly the same. This patch removes the duplicated enum and uses the same for both destination and source cache control. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 3aff676af853..22739c436bc3 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -33,26 +33,15 @@ #define PL330_MAX_IRQS 32 #define PL330_MAX_PERI 32 -enum pl330_srccachectrl { - SCCTRL0, /* Noncacheable and nonbufferable */ - SCCTRL1, /* Bufferable only */ - SCCTRL2, /* Cacheable, but do not allocate */ - SCCTRL3, /* Cacheable and bufferable, but do not allocate */ - SINVALID1, - SINVALID2, - SCCTRL6, /* Cacheable write-through, allocate on reads only */ - SCCTRL7, /* Cacheable write-back, allocate on reads only */ -}; - -enum pl330_dstcachectrl { - DCCTRL0, /* Noncacheable and nonbufferable */ - DCCTRL1, /* Bufferable only */ - DCCTRL2, /* Cacheable, but do not allocate */ - DCCTRL3, /* Cacheable and bufferable, but do not allocate */ - DINVALID1, /* AWCACHE = 0x1000 */ - DINVALID2, - DCCTRL6, /* Cacheable write-through, allocate on writes only */ - DCCTRL7, /* Cacheable write-back, allocate on writes only */ +enum pl330_cachectrl { + CCTRL0, /* Noncacheable and nonbufferable */ + CCTRL1, /* Bufferable only */ + CCTRL2, /* Cacheable, but do not allocate */ + CCTRL3, /* Cacheable and bufferable, but do not allocate */ + INVALID1, /* AWCACHE = 0x1000 */ + INVALID2, + CCTRL6, /* Cacheable write-through, allocate on writes only */ + CCTRL7, /* Cacheable write-back, allocate on writes only */ }; enum pl330_byteswap { @@ -337,8 +326,8 @@ struct pl330_reqcfg { unsigned brst_len:5; unsigned brst_size:3; /* in power of 2 */ - enum pl330_dstcachectrl dcctl; - enum pl330_srccachectrl scctl; + enum pl330_cachectrl dcctl; + enum pl330_cachectrl scctl; enum pl330_byteswap swap; struct pl330_config *pcfg; }; @@ -1490,14 +1479,14 @@ static inline u32 _prepare_ccr(const struct pl330_reqcfg *rqc) static inline bool _is_valid(u32 ccr) { - enum pl330_dstcachectrl dcctl; - enum pl330_srccachectrl scctl; + enum pl330_cachectrl dcctl; + enum pl330_cachectrl scctl; dcctl = (ccr >> CC_DSTCCTRL_SHFT) & CC_DRCCCTRL_MASK; scctl = (ccr >> CC_SRCCCTRL_SHFT) & CC_SRCCCTRL_MASK; - if (dcctl == DINVALID1 || dcctl == DINVALID2 - || scctl == SINVALID1 || scctl == SINVALID2) + if (dcctl == INVALID1 || dcctl == INVALID2 + || scctl == INVALID1 || scctl == INVALID2) return false; else return true; @@ -2485,8 +2474,8 @@ static inline void _init_desc(struct dma_pl330_desc *desc) desc->req.x = &desc->px; desc->req.token = desc; desc->rqcfg.swap = SWAP_NO; - desc->rqcfg.scctl = SCCTRL0; - desc->rqcfg.dcctl = DCCTRL0; + desc->rqcfg.scctl = CCTRL0; + desc->rqcfg.dcctl = CCTRL0; desc->req.cfg = &desc->rqcfg; desc->req.xfer_cb = dma_pl330_rqcb; desc->txd.tx_submit = pl330_tx_submit; -- cgit v1.2.3 From fa01ef38d60096aa689bcc2659aedd4a9ae83cd1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:20 +0200 Subject: dmaengine: pl330: Remove unused pl330_chanstatus struct The pl330_chanstatus struct is completely unused, so remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 29 ----------------------------- 1 file changed, 29 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 22739c436bc3..9121edeb2727 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -375,35 +375,6 @@ struct pl330_req { struct list_head rqd; }; -/* - * To know the status of the channel and DMAC, the client - * provides a pointer to this structure. The PL330 core - * fills it with current information. - */ -struct pl330_chanstatus { - /* - * If the DMAC engine halted due to some error, - * the client should remove-add DMAC. - */ - bool dmac_halted; - /* - * If channel is halted due to some error, - * the client should ABORT/FLUSH and START the channel. - */ - bool faulting; - /* Location of last load */ - u32 src_addr; - /* Location of last store */ - u32 dst_addr; - /* - * Pointer to the currently active req, NULL if channel is - * inactive, even though the requests may be present. - */ - struct pl330_req *top_req; - /* Pointer to req waiting second in the queue if any. */ - struct pl330_req *wait_req; -}; - enum pl330_chan_op { /* Start the channel */ PL330_OP_START, -- cgit v1.2.3 From 7ae342fd6fd2bc1f694cf2c8fcbbeb2d2a017658 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:21 +0200 Subject: dmaengine: pl330: Remove unused dmac_reset callback The dmac_reset() callaback of the pl330_info struct is always set to NULL, so remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 9121edeb2727..f23c5f0b3dac 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -296,11 +296,6 @@ struct pl330_info { void *pl330_data; /* Populated by the PL330 core driver during pl330_add */ struct pl330_config pcfg; - /* - * If the DMAC has some reset mechanism, then the - * client may want to provide pointer to the method. - */ - void (*dmac_reset)(struct pl330_info *pi); }; /** @@ -2024,13 +2019,6 @@ static int pl330_add(struct pl330_info *pi) if (pi->pl330_data) return -EINVAL; - /* - * If the SoC can perform reset on the DMAC, then do it - * before reading its configuration. - */ - if (pi->dmac_reset) - pi->dmac_reset(pi); - regs = pi->base; /* Check if we can handle this DMAC */ -- cgit v1.2.3 From c9392d80ae0762425314fbf1d9210f68da400e12 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:22 +0200 Subject: dmaengine: pl330: Remove unused client_data field form pl330_info The field is completely unused, remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index f23c5f0b3dac..6b61c578c868 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -290,8 +290,6 @@ struct pl330_info { unsigned mcbufsz; /* ioremap'ed address of PL330 registers. */ void __iomem *base; - /* Client can freely use it. */ - void *client_data; /* PL330 core data, Client must not touch it. */ void *pl330_data; /* Populated by the PL330 core driver during pl330_add */ -- cgit v1.2.3 From d5cef121ffa6a2525107e4c58e126ea885911ff7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:23 +0200 Subject: dmaengine: pl330: Remove unused next field form pl330_xfer struct The next field is always NULL, so we can remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 6b61c578c868..80a17a84ab75 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -334,11 +334,6 @@ struct pl330_xfer { u32 dst_addr; /* Size to xfer */ u32 bytes; - /* - * Pointer to next xfer in the list. - * The last xfer in the req must point to NULL. - */ - struct pl330_xfer *next; }; /* The xfer callbacks are made with one of these arguments. */ @@ -1390,16 +1385,12 @@ static int _setup_req(unsigned dry_run, struct pl330_thread *thrd, off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr); x = pxs->r->x; - do { - /* Error if xfer length is not aligned at burst size */ - if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr))) - return -EINVAL; - - pxs->x = x; - off += _setup_xfer(dry_run, &buf[off], pxs); + /* Error if xfer length is not aligned at burst size */ + if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr))) + return -EINVAL; - x = x->next; - } while (x); + pxs->x = x; + off += _setup_xfer(dry_run, &buf[off], pxs); /* DMASEV peripheral/event */ off += _emit_SEV(dry_run, &buf[off], thrd->ev); @@ -2531,7 +2522,6 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) static inline void fill_px(struct pl330_xfer *px, dma_addr_t dst, dma_addr_t src, size_t len) { - px->next = NULL; px->bytes = len; px->dst_addr = dst; px->src_addr = src; -- cgit v1.2.3 From be025329fd4223f3442fffc35f8255bd64d0d526 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:24 +0200 Subject: dmaengine: pl330: Remove unused mc_len field from _pl330_req struct The mc_len is initialized but its value is never read again, so remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 80a17a84ab75..453ce106b5fc 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -398,8 +398,6 @@ enum pl330_cond { struct _pl330_req { u32 mc_bus; void *mc_cpu; - /* Number of bytes taken to setup MC for the req */ - u32 mc_len; struct pl330_req *r; }; @@ -999,7 +997,6 @@ static void mark_free(struct pl330_thread *thrd, int idx) struct _pl330_req *req = &thrd->req[idx]; _emit_END(0, req->mc_cpu); - req->mc_len = 0; thrd->req_running = -1; } @@ -1536,8 +1533,8 @@ static int pl330_submit_req(void *ch_id, struct pl330_req *r) /* Hook the request */ thrd->lstenq = idx; - thrd->req[idx].mc_len = _setup_req(0, thrd, idx, &xs); thrd->req[idx].r = r; + _setup_req(0, thrd, idx, &xs); ret = 0; -- cgit v1.2.3 From 6079d38ca21e80c13af2d8f8a7b062a0e28615c9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:25 +0200 Subject: dmaengine: pl330: Remove useless xfer_cb indirection The xfer_cb callback of the pl330_req struct is always set to the same function. This adds an unnecessary step of indirection. Instead just call the callback function directly. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 62 +++++++++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 38 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 453ce106b5fc..cf2522e429b0 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -351,10 +351,6 @@ struct pl330_req { enum dma_transfer_direction rqtype; /* Index of peripheral for the xfer. */ unsigned peri:5; - /* Unique token for this xfer, set by the client. */ - void *token; - /* Callback to be called after xfer. */ - void (*xfer_cb)(void *token, enum pl330_op_err err); /* If NULL, req will be done at last set parameters. */ struct pl330_reqcfg *cfg; /* Pointer to first xfer in the request. */ @@ -551,12 +547,6 @@ struct dma_pl330_desc { struct dma_pl330_chan *pchan; }; -static inline void _callback(struct pl330_req *r, enum pl330_op_err err) -{ - if (r && r->xfer_cb) - r->xfer_cb(r->token, err); -} - static inline bool _queue_empty(struct pl330_thread *thrd) { return (IS_FREE(&thrd->req[0]) && IS_FREE(&thrd->req[1])) @@ -1544,6 +1534,25 @@ xfer_exit: return ret; } +static void dma_pl330_rqcb(struct pl330_req *req, enum pl330_op_err err) +{ + struct dma_pl330_desc *desc = container_of(req, struct dma_pl330_desc, req); + struct dma_pl330_chan *pch = desc->pchan; + unsigned long flags; + + /* If desc aborted */ + if (!pch) + return; + + spin_lock_irqsave(&pch->lock, flags); + + desc->status = DONE; + + spin_unlock_irqrestore(&pch->lock, flags); + + tasklet_schedule(&pch->task); +} + static void pl330_dotask(unsigned long data) { struct pl330_dmac *pl330 = (struct pl330_dmac *) data; @@ -1585,10 +1594,8 @@ static void pl330_dotask(unsigned long data) err = PL330_ERR_ABORT; spin_unlock_irqrestore(&pl330->lock, flags); - - _callback(thrd->req[1 - thrd->lstenq].r, err); - _callback(thrd->req[thrd->lstenq].r, err); - + dma_pl330_rqcb(thrd->req[1 - thrd->lstenq].r, err); + dma_pl330_rqcb(thrd->req[thrd->lstenq].r, err); spin_lock_irqsave(&pl330->lock, flags); thrd->req[0].r = NULL; @@ -1695,7 +1702,7 @@ static int pl330_update(const struct pl330_info *pi) list_del(&rqdone->rqd); spin_unlock_irqrestore(&pl330->lock, flags); - _callback(rqdone, PL330_ERR_NONE); + dma_pl330_rqcb(rqdone, PL330_ERR_NONE); spin_lock_irqsave(&pl330->lock, flags); } @@ -1852,8 +1859,8 @@ static void pl330_release_channel(void *ch_id) _stop(thrd); - _callback(thrd->req[1 - thrd->lstenq].r, PL330_ERR_ABORT); - _callback(thrd->req[thrd->lstenq].r, PL330_ERR_ABORT); + dma_pl330_rqcb(thrd->req[1 - thrd->lstenq].r, PL330_ERR_ABORT); + dma_pl330_rqcb(thrd->req[thrd->lstenq].r, PL330_ERR_ABORT); pl330 = thrd->dmac; @@ -2207,25 +2214,6 @@ static void pl330_tasklet(unsigned long data) spin_unlock_irqrestore(&pch->lock, flags); } -static void dma_pl330_rqcb(void *token, enum pl330_op_err err) -{ - struct dma_pl330_desc *desc = token; - struct dma_pl330_chan *pch = desc->pchan; - unsigned long flags; - - /* If desc aborted */ - if (!pch) - return; - - spin_lock_irqsave(&pch->lock, flags); - - desc->status = DONE; - - spin_unlock_irqrestore(&pch->lock, flags); - - tasklet_schedule(&pch->task); -} - bool pl330_filter(struct dma_chan *chan, void *param) { u8 *peri_id; @@ -2417,12 +2405,10 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx) static inline void _init_desc(struct dma_pl330_desc *desc) { desc->req.x = &desc->px; - desc->req.token = desc; desc->rqcfg.swap = SWAP_NO; desc->rqcfg.scctl = CCTRL0; desc->rqcfg.dcctl = CCTRL0; desc->req.cfg = &desc->rqcfg; - desc->req.xfer_cb = dma_pl330_rqcb; desc->txd.tx_submit = pl330_tx_submit; INIT_LIST_HEAD(&desc->node); -- cgit v1.2.3 From 65ad60600f5a3bf4c4edfbb95992af6ff2dfc18a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:26 +0200 Subject: dmaengine: pl330: Change type pl330_chid from void * to struct pl330_thread * The pl330_chid field of the dma_pl330_chan struct always holds a pointer to the thread that is associated with the channel. Changing its type form void * to struct pl330_thread makes things more type safe and removes the need for unnecessary typecasts. While we are at it also rename the field from the cryptic pl330_chid to thread. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index cf2522e429b0..f0e9f47e7dc6 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -495,10 +495,11 @@ struct dma_pl330_chan { /* To protect channel manipulation */ spinlock_t lock; - /* Token of a hardware channel thread of PL330 DMAC - * NULL if the channel is available to be acquired. + /* + * Hardware channel thread of PL330 DMAC. NULL if the channel is + * available. */ - void *pl330_chid; + struct pl330_thread *thread; /* For D-to-M and M-to-D channels */ int burst_sz; /* the peripheral fifo width */ @@ -1439,9 +1440,8 @@ static inline bool _is_valid(u32 ccr) * Client is not notified after each xfer unit, just once after all * xfer units are done or some error occurs. */ -static int pl330_submit_req(void *ch_id, struct pl330_req *r) +static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) { - struct pl330_thread *thrd = ch_id; struct pl330_dmac *pl330; struct pl330_info *pi; struct _xfer_spec xs; @@ -1719,9 +1719,8 @@ updt_exit: return ret; } -static int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op) +static int pl330_chan_ctrl(struct pl330_thread *thrd, enum pl330_chan_op op) { - struct pl330_thread *thrd = ch_id; struct pl330_dmac *pl330; unsigned long flags; int ret = 0, active; @@ -1794,7 +1793,7 @@ static bool _chan_ns(const struct pl330_info *pi, int i) /* Upon success, returns IdentityToken for the * allocated channel, NULL otherwise. */ -static void *pl330_request_channel(const struct pl330_info *pi) +static struct pl330_thread *pl330_request_channel(const struct pl330_info *pi) { struct pl330_thread *thrd = NULL; struct pl330_dmac *pl330; @@ -1848,9 +1847,8 @@ static inline void _free_event(struct pl330_thread *thrd, int ev) pl330->events[ev] = -1; } -static void pl330_release_channel(void *ch_id) +static void pl330_release_channel(struct pl330_thread *thrd) { - struct pl330_thread *thrd = ch_id; struct pl330_dmac *pl330; unsigned long flags; @@ -2077,7 +2075,7 @@ static int dmac_free_threads(struct pl330_dmac *pl330) /* Release Channel threads */ for (i = 0; i < chans; i++) { thrd = &pl330->channels[i]; - pl330_release_channel((void *)thrd); + pl330_release_channel(thrd); } /* Free memory */ @@ -2146,8 +2144,7 @@ static inline void fill_queue(struct dma_pl330_chan *pch) if (desc->status == BUSY) continue; - ret = pl330_submit_req(pch->pl330_chid, - &desc->req); + ret = pl330_submit_req(pch->thread, &desc->req); if (!ret) { desc->status = BUSY; } else if (ret == -EAGAIN) { @@ -2183,7 +2180,7 @@ static void pl330_tasklet(unsigned long data) fill_queue(pch); /* Make sure the PL330 Channel thread is active */ - pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START); + pl330_chan_ctrl(pch->thread, PL330_OP_START); while (!list_empty(&pch->completed_list)) { dma_async_tx_callback callback; @@ -2254,8 +2251,8 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) dma_cookie_init(chan); pch->cyclic = false; - pch->pl330_chid = pl330_request_channel(&pdmac->pif); - if (!pch->pl330_chid) { + pch->thread = pl330_request_channel(&pdmac->pif); + if (!pch->thread) { spin_unlock_irqrestore(&pch->lock, flags); return -ENOMEM; } @@ -2281,7 +2278,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned spin_lock_irqsave(&pch->lock, flags); /* FLUSH the PL330 Channel thread */ - pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH); + pl330_chan_ctrl(pch->thread, PL330_OP_FLUSH); /* Mark all desc done */ list_for_each_entry(desc, &pch->submitted_list, node) { @@ -2340,8 +2337,8 @@ static void pl330_free_chan_resources(struct dma_chan *chan) spin_lock_irqsave(&pch->lock, flags); - pl330_release_channel(pch->pl330_chid); - pch->pl330_chid = NULL; + pl330_release_channel(pch->thread); + pch->thread = NULL; if (pch->cyclic) list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); @@ -2887,7 +2884,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) INIT_LIST_HEAD(&pch->work_list); INIT_LIST_HEAD(&pch->completed_list); spin_lock_init(&pch->lock); - pch->pl330_chid = NULL; + pch->thread = NULL; pch->chan.device = pd; pch->dmac = pdmac; -- cgit v1.2.3 From 1b446d2a61c436f7ad542fcdb212d4e51845ac28 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:27 +0200 Subject: dmaengine: pl330: Remove uneccessary ccr validation We know that we do not create invalid ccr settings in this driver. There is no need to validate them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index f0e9f47e7dc6..0209823ca77f 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1420,21 +1420,6 @@ static inline u32 _prepare_ccr(const struct pl330_reqcfg *rqc) return ccr; } -static inline bool _is_valid(u32 ccr) -{ - enum pl330_cachectrl dcctl; - enum pl330_cachectrl scctl; - - dcctl = (ccr >> CC_DSTCCTRL_SHFT) & CC_DRCCCTRL_MASK; - scctl = (ccr >> CC_SRCCCTRL_SHFT) & CC_SRCCCTRL_MASK; - - if (dcctl == INVALID1 || dcctl == INVALID2 - || scctl == INVALID1 || scctl == INVALID2) - return false; - else - return true; -} - /* * Submit a list of xfers after which the client wants notification. * Client is not notified after each xfer unit, just once after all @@ -1495,14 +1480,6 @@ static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) ccr = readl(regs + CC(thrd->id)); } - /* If this req doesn't have valid xfer settings */ - if (!_is_valid(ccr)) { - ret = -EINVAL; - dev_info(thrd->dmac->pinfo->dev, "%s:%d Invalid CCR(%x)!\n", - __func__, __LINE__, ccr); - goto xfer_exit; - } - idx = IS_FREE(&thrd->req[0]) ? 0 : 1; xs.ccr = ccr; -- cgit v1.2.3 From fbbcd9be96a0295e9d127e124f72fa0039f53d8e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:28 +0200 Subject: dmaengine: pl330: Simplify is_manager() Since we keep a pointer to the manager thread it is fairly easy to check if a thread is the manager thread. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 0209823ca77f..c5eeb64dce6f 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -562,13 +562,7 @@ static inline bool _queue_full(struct pl330_thread *thrd) static inline bool is_manager(struct pl330_thread *thrd) { - struct pl330_dmac *pl330 = thrd->dmac; - - /* MANAGER is indexed at the end */ - if (thrd->id == pl330->pinfo->pcfg.num_chan) - return true; - else - return false; + return thrd->dmac->manager == thrd; } /* If manager of the thread is in Non-Secure mode */ -- cgit v1.2.3 From f6f2421c0a1cb6caffc85b13ab8f9bdd8f8278c3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:29 +0200 Subject: dmaengine: pl330: Merge dma_pl330_dmac and pl330_dmac structs Both the dma_pl330_dmac and the pl330_dmac struct have the same lifetime and the separation of them is a relict of this having been two different drivers in the past. Merging them into one struct makes the code a bit simpler as it for example allows to remove the pointers going back and forth between the two structs. While we are at it also directly embed the pl330_info struct into the pl330_dmac struct as this allows to remove some more redundant fields. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 472 +++++++++++++++++++++------------------------------- 1 file changed, 192 insertions(+), 280 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index c5eeb64dce6f..e5fe9c764f53 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -282,20 +282,6 @@ struct pl330_config { u32 irq_ns; }; -/* Handle to the DMAC provided to the PL330 core */ -struct pl330_info { - /* Owning device */ - struct device *dev; - /* Size of MicroCode buffers for each channel. */ - unsigned mcbufsz; - /* ioremap'ed address of PL330 registers. */ - void __iomem *base; - /* PL330 core data, Client must not touch it. */ - void *pl330_data; - /* Populated by the PL330 core driver during pl330_add */ - struct pl330_config pcfg; -}; - /** * Request Configuration. * The PL330 core does not modify this and uses the last @@ -426,30 +412,6 @@ enum pl330_dmac_state { DYING, }; -/* A DMAC */ -struct pl330_dmac { - spinlock_t lock; - /* Holds list of reqs with due callbacks */ - struct list_head req_done; - /* Pointer to platform specific stuff */ - struct pl330_info *pinfo; - /* Maximum possible events/irqs */ - int events[32]; - /* BUS address of MicroCode buffer */ - dma_addr_t mcode_bus; - /* CPU address of MicroCode buffer */ - void *mcode_cpu; - /* List of all Channel threads */ - struct pl330_thread *channels; - /* Pointer to the MANAGER thread */ - struct pl330_thread *manager; - /* To handle bad news in interrupt */ - struct tasklet_struct tasks; - struct _pl330_tbd dmac_tbd; - /* State of DMAC operation */ - enum pl330_dmac_state state; -}; - enum desc_status { /* In the DMAC pool */ FREE, @@ -490,7 +452,7 @@ struct dma_pl330_chan { * As the parent, this DMAC also provides descriptors * to the channel. */ - struct dma_pl330_dmac *dmac; + struct pl330_dmac *dmac; /* To protect channel manipulation */ spinlock_t lock; @@ -510,9 +472,7 @@ struct dma_pl330_chan { bool cyclic; }; -struct dma_pl330_dmac { - struct pl330_info pif; - +struct pl330_dmac { /* DMA-Engine Device */ struct dma_device ddma; @@ -524,6 +484,32 @@ struct dma_pl330_dmac { /* To protect desc_pool manipulation */ spinlock_t pool_lock; + /* Size of MicroCode buffers for each channel. */ + unsigned mcbufsz; + /* ioremap'ed address of PL330 registers. */ + void __iomem *base; + /* Populated by the PL330 core driver during pl330_add */ + struct pl330_config pcfg; + + spinlock_t lock; + /* Maximum possible events/irqs */ + int events[32]; + /* BUS address of MicroCode buffer */ + dma_addr_t mcode_bus; + /* CPU address of MicroCode buffer */ + void *mcode_cpu; + /* List of all Channel threads */ + struct pl330_thread *channels; + /* Pointer to the MANAGER thread */ + struct pl330_thread *manager; + /* To handle bad news in interrupt */ + struct tasklet_struct tasks; + struct _pl330_tbd dmac_tbd; + /* State of DMAC operation */ + enum pl330_dmac_state state; + /* Holds list of reqs with due callbacks */ + struct list_head req_done; + /* Peripheral channels connected to this DMAC */ unsigned int num_peripherals; struct dma_pl330_chan *peripherals; /* keep at end */ @@ -568,9 +554,7 @@ static inline bool is_manager(struct pl330_thread *thrd) /* If manager of the thread is in Non-Secure mode */ static inline bool _manager_ns(struct pl330_thread *thrd) { - struct pl330_dmac *pl330 = thrd->dmac; - - return (pl330->pinfo->pcfg.mode & DMAC_MODE_NS) ? true : false; + return (thrd->dmac->pcfg.mode & DMAC_MODE_NS) ? true : false; } static inline u32 get_revision(u32 periph_id) @@ -928,7 +912,7 @@ static inline u32 _emit_GO(unsigned dry_run, u8 buf[], /* Returns Time-Out */ static bool _until_dmac_idle(struct pl330_thread *thrd) { - void __iomem *regs = thrd->dmac->pinfo->base; + void __iomem *regs = thrd->dmac->base; unsigned long loops = msecs_to_loops(5); do { @@ -948,7 +932,7 @@ static bool _until_dmac_idle(struct pl330_thread *thrd) static inline void _execute_DBGINSN(struct pl330_thread *thrd, u8 insn[], bool as_manager) { - void __iomem *regs = thrd->dmac->pinfo->base; + void __iomem *regs = thrd->dmac->base; u32 val; val = (insn[0] << 16) | (insn[1] << 24); @@ -963,7 +947,7 @@ static inline void _execute_DBGINSN(struct pl330_thread *thrd, /* If timed out due to halted state-machine */ if (_until_dmac_idle(thrd)) { - dev_err(thrd->dmac->pinfo->dev, "DMAC halted!\n"); + dev_err(thrd->dmac->ddma.dev, "DMAC halted!\n"); return; } @@ -988,7 +972,7 @@ static void mark_free(struct pl330_thread *thrd, int idx) static inline u32 _state(struct pl330_thread *thrd) { - void __iomem *regs = thrd->dmac->pinfo->base; + void __iomem *regs = thrd->dmac->base; u32 val; if (is_manager(thrd)) @@ -1046,7 +1030,7 @@ static inline u32 _state(struct pl330_thread *thrd) static void _stop(struct pl330_thread *thrd) { - void __iomem *regs = thrd->dmac->pinfo->base; + void __iomem *regs = thrd->dmac->base; u8 insn[6] = {0, 0, 0, 0, 0, 0}; if (_state(thrd) == PL330_STATE_FAULT_COMPLETING) @@ -1069,7 +1053,7 @@ static void _stop(struct pl330_thread *thrd) /* Start doing req 'idx' of thread 'thrd' */ static bool _trigger(struct pl330_thread *thrd) { - void __iomem *regs = thrd->dmac->pinfo->base; + void __iomem *regs = thrd->dmac->base; struct _pl330_req *req; struct pl330_req *r; struct _arg_GO go; @@ -1107,7 +1091,7 @@ static bool _trigger(struct pl330_thread *thrd) /* See 'Abort Sources' point-4 at Page 2-25 */ if (_manager_ns(thrd) && !ns) - dev_info(thrd->dmac->pinfo->dev, "%s:%d Recipe for ABORT!\n", + dev_info(thrd->dmac->ddma.dev, "%s:%d Recipe for ABORT!\n", __func__, __LINE__); go.chan = thrd->id; @@ -1421,8 +1405,7 @@ static inline u32 _prepare_ccr(const struct pl330_reqcfg *rqc) */ static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) { - struct pl330_dmac *pl330; - struct pl330_info *pi; + struct pl330_dmac *pl330 = thrd->dmac; struct _xfer_spec xs; unsigned long flags; void __iomem *regs; @@ -1434,20 +1417,18 @@ static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) if (!r || !thrd || thrd->free) return -EINVAL; - pl330 = thrd->dmac; - pi = pl330->pinfo; - regs = pi->base; + regs = thrd->dmac->base; if (pl330->state == DYING || pl330->dmac_tbd.reset_chan & (1 << thrd->id)) { - dev_info(thrd->dmac->pinfo->dev, "%s:%d\n", + dev_info(thrd->dmac->ddma.dev, "%s:%d\n", __func__, __LINE__); return -EAGAIN; } /* If request for non-existing peripheral */ - if (r->rqtype != DMA_MEM_TO_MEM && r->peri >= pi->pcfg.num_peri) { - dev_info(thrd->dmac->pinfo->dev, + if (r->rqtype != DMA_MEM_TO_MEM && r->peri >= pl330->pcfg.num_peri) { + dev_info(thrd->dmac->ddma.dev, "%s:%d Invalid peripheral(%u)!\n", __func__, __LINE__, r->peri); return -EINVAL; @@ -1484,9 +1465,8 @@ static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) if (ret < 0) goto xfer_exit; - if (ret > pi->mcbufsz / 2) { - dev_info(thrd->dmac->pinfo->dev, - "%s:%d Trying increasing mcbufsz\n", + if (ret > pl330->mcbufsz / 2) { + dev_info(pl330->ddma.dev, "%s:%d Trying increasing mcbufsz\n", __func__, __LINE__); ret = -ENOMEM; goto xfer_exit; @@ -1527,7 +1507,6 @@ static void dma_pl330_rqcb(struct pl330_req *req, enum pl330_op_err err) static void pl330_dotask(unsigned long data) { struct pl330_dmac *pl330 = (struct pl330_dmac *) data; - struct pl330_info *pi = pl330->pinfo; unsigned long flags; int i; @@ -1545,16 +1524,16 @@ static void pl330_dotask(unsigned long data) if (pl330->dmac_tbd.reset_mngr) { _stop(pl330->manager); /* Reset all channels */ - pl330->dmac_tbd.reset_chan = (1 << pi->pcfg.num_chan) - 1; + pl330->dmac_tbd.reset_chan = (1 << pl330->pcfg.num_chan) - 1; /* Clear the reset flag */ pl330->dmac_tbd.reset_mngr = false; } - for (i = 0; i < pi->pcfg.num_chan; i++) { + for (i = 0; i < pl330->pcfg.num_chan; i++) { if (pl330->dmac_tbd.reset_chan & (1 << i)) { struct pl330_thread *thrd = &pl330->channels[i]; - void __iomem *regs = pi->base; + void __iomem *regs = pl330->base; enum pl330_op_err err; _stop(thrd); @@ -1585,20 +1564,15 @@ static void pl330_dotask(unsigned long data) } /* Returns 1 if state was updated, 0 otherwise */ -static int pl330_update(const struct pl330_info *pi) +static int pl330_update(struct pl330_dmac *pl330) { struct pl330_req *rqdone, *tmp; - struct pl330_dmac *pl330; unsigned long flags; void __iomem *regs; u32 val; int id, ev, ret = 0; - if (!pi || !pi->pl330_data) - return 0; - - regs = pi->base; - pl330 = pi->pl330_data; + regs = pl330->base; spin_lock_irqsave(&pl330->lock, flags); @@ -1608,13 +1582,13 @@ static int pl330_update(const struct pl330_info *pi) else pl330->dmac_tbd.reset_mngr = false; - val = readl(regs + FSC) & ((1 << pi->pcfg.num_chan) - 1); + val = readl(regs + FSC) & ((1 << pl330->pcfg.num_chan) - 1); pl330->dmac_tbd.reset_chan |= val; if (val) { int i = 0; - while (i < pi->pcfg.num_chan) { + while (i < pl330->pcfg.num_chan) { if (val & (1 << i)) { - dev_info(pi->dev, + dev_info(pl330->ddma.dev, "Reset Channel-%d\t CS-%x FTC-%x\n", i, readl(regs + CS(i)), readl(regs + FTC(i))); @@ -1626,15 +1600,16 @@ static int pl330_update(const struct pl330_info *pi) /* Check which event happened i.e, thread notified */ val = readl(regs + ES); - if (pi->pcfg.num_events < 32 - && val & ~((1 << pi->pcfg.num_events) - 1)) { + if (pl330->pcfg.num_events < 32 + && val & ~((1 << pl330->pcfg.num_events) - 1)) { pl330->dmac_tbd.reset_dmac = true; - dev_err(pi->dev, "%s:%d Unexpected!\n", __func__, __LINE__); + dev_err(pl330->ddma.dev, "%s:%d Unexpected!\n", __func__, + __LINE__); ret = 1; goto updt_exit; } - for (ev = 0; ev < pi->pcfg.num_events; ev++) { + for (ev = 0; ev < pl330->pcfg.num_events; ev++) { if (val & (1 << ev)) { /* Event occurred */ struct pl330_thread *thrd; u32 inten = readl(regs + INTEN); @@ -1744,10 +1719,9 @@ static int pl330_chan_ctrl(struct pl330_thread *thrd, enum pl330_chan_op op) static inline int _alloc_event(struct pl330_thread *thrd) { struct pl330_dmac *pl330 = thrd->dmac; - struct pl330_info *pi = pl330->pinfo; int ev; - for (ev = 0; ev < pi->pcfg.num_events; ev++) + for (ev = 0; ev < pl330->pcfg.num_events; ev++) if (pl330->events[ev] == -1) { pl330->events[ev] = thrd->id; return ev; @@ -1756,37 +1730,31 @@ static inline int _alloc_event(struct pl330_thread *thrd) return -1; } -static bool _chan_ns(const struct pl330_info *pi, int i) +static bool _chan_ns(const struct pl330_dmac *pl330, int i) { - return pi->pcfg.irq_ns & (1 << i); + return pl330->pcfg.irq_ns & (1 << i); } /* Upon success, returns IdentityToken for the * allocated channel, NULL otherwise. */ -static struct pl330_thread *pl330_request_channel(const struct pl330_info *pi) +static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) { struct pl330_thread *thrd = NULL; - struct pl330_dmac *pl330; unsigned long flags; int chans, i; - if (!pi || !pi->pl330_data) - return NULL; - - pl330 = pi->pl330_data; - if (pl330->state == DYING) return NULL; - chans = pi->pcfg.num_chan; + chans = pl330->pcfg.num_chan; spin_lock_irqsave(&pl330->lock, flags); for (i = 0; i < chans; i++) { thrd = &pl330->channels[i]; if ((thrd->free) && (!_manager_ns(thrd) || - _chan_ns(pi, i))) { + _chan_ns(pl330, i))) { thrd->ev = _alloc_event(thrd); if (thrd->ev >= 0) { thrd->free = false; @@ -1810,10 +1778,9 @@ static struct pl330_thread *pl330_request_channel(const struct pl330_info *pi) static inline void _free_event(struct pl330_thread *thrd, int ev) { struct pl330_dmac *pl330 = thrd->dmac; - struct pl330_info *pi = pl330->pinfo; /* If the event is valid and was held by the thread */ - if (ev >= 0 && ev < pi->pcfg.num_events + if (ev >= 0 && ev < pl330->pcfg.num_events && pl330->events[ev] == thrd->id) pl330->events[ev] = -1; } @@ -1842,72 +1809,70 @@ static void pl330_release_channel(struct pl330_thread *thrd) /* Initialize the structure for PL330 configuration, that can be used * by the client driver the make best use of the DMAC */ -static void read_dmac_config(struct pl330_info *pi) +static void read_dmac_config(struct pl330_dmac *pl330) { - void __iomem *regs = pi->base; + void __iomem *regs = pl330->base; u32 val; val = readl(regs + CRD) >> CRD_DATA_WIDTH_SHIFT; val &= CRD_DATA_WIDTH_MASK; - pi->pcfg.data_bus_width = 8 * (1 << val); + pl330->pcfg.data_bus_width = 8 * (1 << val); val = readl(regs + CRD) >> CRD_DATA_BUFF_SHIFT; val &= CRD_DATA_BUFF_MASK; - pi->pcfg.data_buf_dep = val + 1; + pl330->pcfg.data_buf_dep = val + 1; val = readl(regs + CR0) >> CR0_NUM_CHANS_SHIFT; val &= CR0_NUM_CHANS_MASK; val += 1; - pi->pcfg.num_chan = val; + pl330->pcfg.num_chan = val; val = readl(regs + CR0); if (val & CR0_PERIPH_REQ_SET) { val = (val >> CR0_NUM_PERIPH_SHIFT) & CR0_NUM_PERIPH_MASK; val += 1; - pi->pcfg.num_peri = val; - pi->pcfg.peri_ns = readl(regs + CR4); + pl330->pcfg.num_peri = val; + pl330->pcfg.peri_ns = readl(regs + CR4); } else { - pi->pcfg.num_peri = 0; + pl330->pcfg.num_peri = 0; } val = readl(regs + CR0); if (val & CR0_BOOT_MAN_NS) - pi->pcfg.mode |= DMAC_MODE_NS; + pl330->pcfg.mode |= DMAC_MODE_NS; else - pi->pcfg.mode &= ~DMAC_MODE_NS; + pl330->pcfg.mode &= ~DMAC_MODE_NS; val = readl(regs + CR0) >> CR0_NUM_EVENTS_SHIFT; val &= CR0_NUM_EVENTS_MASK; val += 1; - pi->pcfg.num_events = val; + pl330->pcfg.num_events = val; - pi->pcfg.irq_ns = readl(regs + CR3); + pl330->pcfg.irq_ns = readl(regs + CR3); } static inline void _reset_thread(struct pl330_thread *thrd) { struct pl330_dmac *pl330 = thrd->dmac; - struct pl330_info *pi = pl330->pinfo; thrd->req[0].mc_cpu = pl330->mcode_cpu - + (thrd->id * pi->mcbufsz); + + (thrd->id * pl330->mcbufsz); thrd->req[0].mc_bus = pl330->mcode_bus - + (thrd->id * pi->mcbufsz); + + (thrd->id * pl330->mcbufsz); thrd->req[0].r = NULL; mark_free(thrd, 0); thrd->req[1].mc_cpu = thrd->req[0].mc_cpu - + pi->mcbufsz / 2; + + pl330->mcbufsz / 2; thrd->req[1].mc_bus = thrd->req[0].mc_bus - + pi->mcbufsz / 2; + + pl330->mcbufsz / 2; thrd->req[1].r = NULL; mark_free(thrd, 1); } static int dmac_alloc_threads(struct pl330_dmac *pl330) { - struct pl330_info *pi = pl330->pinfo; - int chans = pi->pcfg.num_chan; + int chans = pl330->pcfg.num_chan; struct pl330_thread *thrd; int i; @@ -1938,29 +1903,28 @@ static int dmac_alloc_threads(struct pl330_dmac *pl330) static int dmac_alloc_resources(struct pl330_dmac *pl330) { - struct pl330_info *pi = pl330->pinfo; - int chans = pi->pcfg.num_chan; + int chans = pl330->pcfg.num_chan; int ret; /* * Alloc MicroCode buffer for 'chans' Channel threads. * A channel's buffer offset is (Channel_Id * MCODE_BUFF_PERCHAN) */ - pl330->mcode_cpu = dma_alloc_coherent(pi->dev, - chans * pi->mcbufsz, + pl330->mcode_cpu = dma_alloc_coherent(pl330->ddma.dev, + chans * pl330->mcbufsz, &pl330->mcode_bus, GFP_KERNEL); if (!pl330->mcode_cpu) { - dev_err(pi->dev, "%s:%d Can't allocate memory!\n", + dev_err(pl330->ddma.dev, "%s:%d Can't allocate memory!\n", __func__, __LINE__); return -ENOMEM; } ret = dmac_alloc_threads(pl330); if (ret) { - dev_err(pi->dev, "%s:%d Can't to create channels for DMAC!\n", + dev_err(pl330->ddma.dev, "%s:%d Can't to create channels for DMAC!\n", __func__, __LINE__); - dma_free_coherent(pi->dev, - chans * pi->mcbufsz, + dma_free_coherent(pl330->ddma.dev, + chans * pl330->mcbufsz, pl330->mcode_cpu, pl330->mcode_bus); return ret; } @@ -1968,64 +1932,45 @@ static int dmac_alloc_resources(struct pl330_dmac *pl330) return 0; } -static int pl330_add(struct pl330_info *pi) +static int pl330_add(struct pl330_dmac *pl330) { - struct pl330_dmac *pl330; void __iomem *regs; int i, ret; - if (!pi || !pi->dev) - return -EINVAL; - - /* If already added */ - if (pi->pl330_data) - return -EINVAL; - - regs = pi->base; + regs = pl330->base; /* Check if we can handle this DMAC */ - if ((pi->pcfg.periph_id & 0xfffff) != PERIPH_ID_VAL) { - dev_err(pi->dev, "PERIPH_ID 0x%x !\n", pi->pcfg.periph_id); + if ((pl330->pcfg.periph_id & 0xfffff) != PERIPH_ID_VAL) { + dev_err(pl330->ddma.dev, "PERIPH_ID 0x%x !\n", + pl330->pcfg.periph_id); return -EINVAL; } /* Read the configuration of the DMAC */ - read_dmac_config(pi); + read_dmac_config(pl330); - if (pi->pcfg.num_events == 0) { - dev_err(pi->dev, "%s:%d Can't work without events!\n", + if (pl330->pcfg.num_events == 0) { + dev_err(pl330->ddma.dev, "%s:%d Can't work without events!\n", __func__, __LINE__); return -EINVAL; } - pl330 = kzalloc(sizeof(*pl330), GFP_KERNEL); - if (!pl330) { - dev_err(pi->dev, "%s:%d Can't allocate memory!\n", - __func__, __LINE__); - return -ENOMEM; - } - - /* Assign the info structure and private data */ - pl330->pinfo = pi; - pi->pl330_data = pl330; - spin_lock_init(&pl330->lock); INIT_LIST_HEAD(&pl330->req_done); /* Use default MC buffer size if not provided */ - if (!pi->mcbufsz) - pi->mcbufsz = MCODE_BUFF_PER_REQ * 2; + if (!pl330->mcbufsz) + pl330->mcbufsz = MCODE_BUFF_PER_REQ * 2; /* Mark all events as free */ - for (i = 0; i < pi->pcfg.num_events; i++) + for (i = 0; i < pl330->pcfg.num_events; i++) pl330->events[i] = -1; /* Allocate resources needed by the DMAC */ ret = dmac_alloc_resources(pl330); if (ret) { - dev_err(pi->dev, "Unable to create channels for DMAC\n"); - kfree(pl330); + dev_err(pl330->ddma.dev, "Unable to create channels for DMAC\n"); return ret; } @@ -2038,13 +1983,11 @@ static int pl330_add(struct pl330_info *pi) static int dmac_free_threads(struct pl330_dmac *pl330) { - struct pl330_info *pi = pl330->pinfo; - int chans = pi->pcfg.num_chan; struct pl330_thread *thrd; int i; /* Release Channel threads */ - for (i = 0; i < chans; i++) { + for (i = 0; i < pl330->pcfg.num_chan; i++) { thrd = &pl330->channels[i]; pl330_release_channel(thrd); } @@ -2055,35 +1998,18 @@ static int dmac_free_threads(struct pl330_dmac *pl330) return 0; } -static void dmac_free_resources(struct pl330_dmac *pl330) -{ - struct pl330_info *pi = pl330->pinfo; - int chans = pi->pcfg.num_chan; - - dmac_free_threads(pl330); - - dma_free_coherent(pi->dev, chans * pi->mcbufsz, - pl330->mcode_cpu, pl330->mcode_bus); -} - -static void pl330_del(struct pl330_info *pi) +static void pl330_del(struct pl330_dmac *pl330) { - struct pl330_dmac *pl330; - - if (!pi || !pi->pl330_data) - return; - - pl330 = pi->pl330_data; - pl330->state = UNINIT; tasklet_kill(&pl330->tasks); /* Free DMAC resources */ - dmac_free_resources(pl330); + dmac_free_threads(pl330); - kfree(pl330); - pi->pl330_data = NULL; + dma_free_coherent(pl330->ddma.dev, + pl330->pcfg.num_chan * pl330->mcbufsz, pl330->mcode_cpu, + pl330->mcode_bus); } /* forward declaration */ @@ -2124,7 +2050,7 @@ static inline void fill_queue(struct dma_pl330_chan *pch) } else { /* Unacceptable request */ desc->status = DONE; - dev_err(pch->dmac->pif.dev, "%s:%d Bad Desc(%d)\n", + dev_err(pch->dmac->ddma.dev, "%s:%d Bad Desc(%d)\n", __func__, __LINE__, desc->txd.cookie); tasklet_schedule(&pch->task); } @@ -2198,23 +2124,26 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { int count = dma_spec->args_count; - struct dma_pl330_dmac *pdmac = ofdma->of_dma_data; + struct pl330_dmac *pl330 = ofdma->of_dma_data; unsigned int chan_id; + if (!pl330) + return NULL; + if (count != 1) return NULL; chan_id = dma_spec->args[0]; - if (chan_id >= pdmac->num_peripherals) + if (chan_id >= pl330->num_peripherals) return NULL; - return dma_get_slave_channel(&pdmac->peripherals[chan_id].chan); + return dma_get_slave_channel(&pl330->peripherals[chan_id].chan); } static int pl330_alloc_chan_resources(struct dma_chan *chan) { struct dma_pl330_chan *pch = to_pchan(chan); - struct dma_pl330_dmac *pdmac = pch->dmac; + struct pl330_dmac *pl330 = pch->dmac; unsigned long flags; spin_lock_irqsave(&pch->lock, flags); @@ -2222,7 +2151,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) dma_cookie_init(chan); pch->cyclic = false; - pch->thread = pl330_request_channel(&pdmac->pif); + pch->thread = pl330_request_channel(pl330); if (!pch->thread) { spin_unlock_irqrestore(&pch->lock, flags); return -ENOMEM; @@ -2240,7 +2169,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned struct dma_pl330_chan *pch = to_pchan(chan); struct dma_pl330_desc *desc; unsigned long flags; - struct dma_pl330_dmac *pdmac = pch->dmac; + struct pl330_dmac *pl330 = pch->dmac; struct dma_slave_config *slave_config; LIST_HEAD(list); @@ -2267,9 +2196,9 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned dma_cookie_complete(&desc->txd); } - list_splice_tail_init(&pch->submitted_list, &pdmac->desc_pool); - list_splice_tail_init(&pch->work_list, &pdmac->desc_pool); - list_splice_tail_init(&pch->completed_list, &pdmac->desc_pool); + list_splice_tail_init(&pch->submitted_list, &pl330->desc_pool); + list_splice_tail_init(&pch->work_list, &pl330->desc_pool); + list_splice_tail_init(&pch->completed_list, &pl330->desc_pool); spin_unlock_irqrestore(&pch->lock, flags); break; case DMA_SLAVE_CONFIG: @@ -2292,7 +2221,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned } break; default: - dev_err(pch->dmac->pif.dev, "Not supported command.\n"); + dev_err(pch->dmac->ddma.dev, "Not supported command.\n"); return -ENXIO; } @@ -2383,44 +2312,37 @@ static inline void _init_desc(struct dma_pl330_desc *desc) } /* Returns the number of descriptors added to the DMAC pool */ -static int add_desc(struct dma_pl330_dmac *pdmac, gfp_t flg, int count) +static int add_desc(struct pl330_dmac *pl330, gfp_t flg, int count) { struct dma_pl330_desc *desc; unsigned long flags; int i; - if (!pdmac) - return 0; - desc = kcalloc(count, sizeof(*desc), flg); if (!desc) return 0; - spin_lock_irqsave(&pdmac->pool_lock, flags); + spin_lock_irqsave(&pl330->pool_lock, flags); for (i = 0; i < count; i++) { _init_desc(&desc[i]); - list_add_tail(&desc[i].node, &pdmac->desc_pool); + list_add_tail(&desc[i].node, &pl330->desc_pool); } - spin_unlock_irqrestore(&pdmac->pool_lock, flags); + spin_unlock_irqrestore(&pl330->pool_lock, flags); return count; } -static struct dma_pl330_desc * -pluck_desc(struct dma_pl330_dmac *pdmac) +static struct dma_pl330_desc *pluck_desc(struct pl330_dmac *pl330) { struct dma_pl330_desc *desc = NULL; unsigned long flags; - if (!pdmac) - return NULL; + spin_lock_irqsave(&pl330->pool_lock, flags); - spin_lock_irqsave(&pdmac->pool_lock, flags); - - if (!list_empty(&pdmac->desc_pool)) { - desc = list_entry(pdmac->desc_pool.next, + if (!list_empty(&pl330->desc_pool)) { + desc = list_entry(pl330->desc_pool.next, struct dma_pl330_desc, node); list_del_init(&desc->node); @@ -2429,29 +2351,29 @@ pluck_desc(struct dma_pl330_dmac *pdmac) desc->txd.callback = NULL; } - spin_unlock_irqrestore(&pdmac->pool_lock, flags); + spin_unlock_irqrestore(&pl330->pool_lock, flags); return desc; } static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) { - struct dma_pl330_dmac *pdmac = pch->dmac; + struct pl330_dmac *pl330 = pch->dmac; u8 *peri_id = pch->chan.private; struct dma_pl330_desc *desc; /* Pluck one desc from the pool of DMAC */ - desc = pluck_desc(pdmac); + desc = pluck_desc(pl330); /* If the DMAC pool is empty, alloc new */ if (!desc) { - if (!add_desc(pdmac, GFP_ATOMIC, 1)) + if (!add_desc(pl330, GFP_ATOMIC, 1)) return NULL; /* Try again */ - desc = pluck_desc(pdmac); + desc = pluck_desc(pl330); if (!desc) { - dev_err(pch->dmac->pif.dev, + dev_err(pch->dmac->ddma.dev, "%s:%d ALERT!\n", __func__, __LINE__); return NULL; } @@ -2463,7 +2385,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) async_tx_ack(&desc->txd); desc->req.peri = peri_id ? pch->chan.chan_id : 0; - desc->rqcfg.pcfg = &pch->dmac->pif.pcfg; + desc->rqcfg.pcfg = &pch->dmac->pcfg; dma_async_tx_descriptor_init(&desc->txd, &pch->chan); @@ -2485,7 +2407,7 @@ __pl330_prep_dma_memcpy(struct dma_pl330_chan *pch, dma_addr_t dst, struct dma_pl330_desc *desc = pl330_get_desc(pch); if (!desc) { - dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n", + dev_err(pch->dmac->ddma.dev, "%s:%d Unable to fetch desc\n", __func__, __LINE__); return NULL; } @@ -2509,11 +2431,11 @@ __pl330_prep_dma_memcpy(struct dma_pl330_chan *pch, dma_addr_t dst, static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) { struct dma_pl330_chan *pch = desc->pchan; - struct pl330_info *pi = &pch->dmac->pif; + struct pl330_dmac *pl330 = pch->dmac; int burst_len; - burst_len = pi->pcfg.data_bus_width / 8; - burst_len *= pi->pcfg.data_buf_dep; + burst_len = pl330->pcfg.data_bus_width / 8; + burst_len *= pl330->pcfg.data_buf_dep; burst_len >>= desc->rqcfg.brst_size; /* src/dst_burst_len can't be more than 16 */ @@ -2536,7 +2458,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( { struct dma_pl330_desc *desc = NULL, *first = NULL; struct dma_pl330_chan *pch = to_pchan(chan); - struct dma_pl330_dmac *pdmac = pch->dmac; + struct pl330_dmac *pl330 = pch->dmac; unsigned int i; dma_addr_t dst; dma_addr_t src; @@ -2545,7 +2467,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( return NULL; if (!is_slave_direction(direction)) { - dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n", + dev_err(pch->dmac->ddma.dev, "%s:%d Invalid dma direction\n", __func__, __LINE__); return NULL; } @@ -2553,23 +2475,23 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( for (i = 0; i < len / period_len; i++) { desc = pl330_get_desc(pch); if (!desc) { - dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n", + dev_err(pch->dmac->ddma.dev, "%s:%d Unable to fetch desc\n", __func__, __LINE__); if (!first) return NULL; - spin_lock_irqsave(&pdmac->pool_lock, flags); + spin_lock_irqsave(&pl330->pool_lock, flags); while (!list_empty(&first->node)) { desc = list_entry(first->node.next, struct dma_pl330_desc, node); - list_move_tail(&desc->node, &pdmac->desc_pool); + list_move_tail(&desc->node, &pl330->desc_pool); } - list_move_tail(&first->node, &pdmac->desc_pool); + list_move_tail(&first->node, &pl330->desc_pool); - spin_unlock_irqrestore(&pdmac->pool_lock, flags); + spin_unlock_irqrestore(&pl330->pool_lock, flags); return NULL; } @@ -2619,14 +2541,12 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, { struct dma_pl330_desc *desc; struct dma_pl330_chan *pch = to_pchan(chan); - struct pl330_info *pi; + struct pl330_dmac *pl330 = pch->dmac; int burst; if (unlikely(!pch || !len)) return NULL; - pi = &pch->dmac->pif; - desc = __pl330_prep_dma_memcpy(pch, dst, src, len); if (!desc) return NULL; @@ -2636,7 +2556,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, desc->req.rqtype = DMA_MEM_TO_MEM; /* Select max possible burst size */ - burst = pi->pcfg.data_bus_width / 8; + burst = pl330->pcfg.data_bus_width / 8; while (burst > 1) { if (!(len % burst)) @@ -2655,7 +2575,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, return &desc->txd; } -static void __pl330_giveback_desc(struct dma_pl330_dmac *pdmac, +static void __pl330_giveback_desc(struct pl330_dmac *pl330, struct dma_pl330_desc *first) { unsigned long flags; @@ -2664,17 +2584,17 @@ static void __pl330_giveback_desc(struct dma_pl330_dmac *pdmac, if (!first) return; - spin_lock_irqsave(&pdmac->pool_lock, flags); + spin_lock_irqsave(&pl330->pool_lock, flags); while (!list_empty(&first->node)) { desc = list_entry(first->node.next, struct dma_pl330_desc, node); - list_move_tail(&desc->node, &pdmac->desc_pool); + list_move_tail(&desc->node, &pl330->desc_pool); } - list_move_tail(&first->node, &pdmac->desc_pool); + list_move_tail(&first->node, &pl330->desc_pool); - spin_unlock_irqrestore(&pdmac->pool_lock, flags); + spin_unlock_irqrestore(&pl330->pool_lock, flags); } static struct dma_async_tx_descriptor * @@ -2699,12 +2619,12 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc = pl330_get_desc(pch); if (!desc) { - struct dma_pl330_dmac *pdmac = pch->dmac; + struct pl330_dmac *pl330 = pch->dmac; - dev_err(pch->dmac->pif.dev, + dev_err(pch->dmac->ddma.dev, "%s:%d Unable to fetch desc\n", __func__, __LINE__); - __pl330_giveback_desc(pdmac, first); + __pl330_giveback_desc(pl330, first); return NULL; } @@ -2768,9 +2688,9 @@ static int pl330_probe(struct amba_device *adev, const struct amba_id *id) { struct dma_pl330_platdata *pdat; - struct dma_pl330_dmac *pdmac; + struct pl330_config *pcfg; + struct pl330_dmac *pl330; struct dma_pl330_chan *pch, *_p; - struct pl330_info *pi; struct dma_device *pd; struct resource *res; int i, ret, irq; @@ -2783,30 +2703,27 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) return ret; /* Allocate a new DMAC and its Channels */ - pdmac = devm_kzalloc(&adev->dev, sizeof(*pdmac), GFP_KERNEL); - if (!pdmac) { + pl330 = devm_kzalloc(&adev->dev, sizeof(*pl330), GFP_KERNEL); + if (!pl330) { dev_err(&adev->dev, "unable to allocate mem\n"); return -ENOMEM; } - pi = &pdmac->pif; - pi->dev = &adev->dev; - pi->pl330_data = NULL; - pi->mcbufsz = pdat ? pdat->mcbuf_sz : 0; + pl330->mcbufsz = pdat ? pdat->mcbuf_sz : 0; res = &adev->res; - pi->base = devm_ioremap_resource(&adev->dev, res); - if (IS_ERR(pi->base)) - return PTR_ERR(pi->base); + pl330->base = devm_ioremap_resource(&adev->dev, res); + if (IS_ERR(pl330->base)) + return PTR_ERR(pl330->base); - amba_set_drvdata(adev, pdmac); + amba_set_drvdata(adev, pl330); for (i = 0; i < AMBA_NR_IRQS; i++) { irq = adev->irq[i]; if (irq) { ret = devm_request_irq(&adev->dev, irq, pl330_irq_handler, 0, - dev_name(&adev->dev), pi); + dev_name(&adev->dev), pl330); if (ret) return ret; } else { @@ -2814,38 +2731,40 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) } } - pi->pcfg.periph_id = adev->periphid; - ret = pl330_add(pi); + pcfg = &pl330->pcfg; + + pcfg->periph_id = adev->periphid; + ret = pl330_add(pl330); if (ret) return ret; - INIT_LIST_HEAD(&pdmac->desc_pool); - spin_lock_init(&pdmac->pool_lock); + INIT_LIST_HEAD(&pl330->desc_pool); + spin_lock_init(&pl330->pool_lock); /* Create a descriptor pool of default size */ - if (!add_desc(pdmac, GFP_KERNEL, NR_DEFAULT_DESC)) + if (!add_desc(pl330, GFP_KERNEL, NR_DEFAULT_DESC)) dev_warn(&adev->dev, "unable to allocate desc\n"); - pd = &pdmac->ddma; + pd = &pl330->ddma; INIT_LIST_HEAD(&pd->channels); /* Initialize channel parameters */ if (pdat) - num_chan = max_t(int, pdat->nr_valid_peri, pi->pcfg.num_chan); + num_chan = max_t(int, pdat->nr_valid_peri, pcfg->num_chan); else - num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan); + num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan); - pdmac->num_peripherals = num_chan; + pl330->num_peripherals = num_chan; - pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); - if (!pdmac->peripherals) { + pl330->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); + if (!pl330->peripherals) { ret = -ENOMEM; - dev_err(&adev->dev, "unable to allocate pdmac->peripherals\n"); + dev_err(&adev->dev, "unable to allocate pl330->peripherals\n"); goto probe_err2; } for (i = 0; i < num_chan; i++) { - pch = &pdmac->peripherals[i]; + pch = &pl330->peripherals[i]; if (!adev->dev.of_node) pch->chan.private = pdat ? &pdat->peri_id[i] : NULL; else @@ -2857,7 +2776,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&pch->lock); pch->thread = NULL; pch->chan.device = pd; - pch->dmac = pdmac; + pch->dmac = pl330; /* Add the channel to the DMAC list */ list_add_tail(&pch->chan.device_node, &pd->channels); @@ -2868,7 +2787,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pd->cap_mask = pdat->cap_mask; } else { dma_cap_set(DMA_MEMCPY, pd->cap_mask); - if (pi->pcfg.num_peri) { + if (pcfg->num_peri) { dma_cap_set(DMA_SLAVE, pd->cap_mask); dma_cap_set(DMA_CYCLIC, pd->cap_mask); dma_cap_set(DMA_PRIVATE, pd->cap_mask); @@ -2893,14 +2812,14 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) if (adev->dev.of_node) { ret = of_dma_controller_register(adev->dev.of_node, - of_dma_pl330_xlate, pdmac); + of_dma_pl330_xlate, pl330); if (ret) { dev_err(&adev->dev, "unable to register DMA to the generic DT DMA helpers\n"); } } - adev->dev.dma_parms = &pdmac->dma_parms; + adev->dev.dma_parms = &pl330->dma_parms; /* * This is the limit for transfers with a buswidth of 1, larger @@ -2915,14 +2834,13 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) "Loaded driver for PL330 DMAC-%d\n", adev->periphid); dev_info(&adev->dev, "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n", - pi->pcfg.data_buf_dep, - pi->pcfg.data_bus_width / 8, pi->pcfg.num_chan, - pi->pcfg.num_peri, pi->pcfg.num_events); + pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, + pcfg->num_peri, pcfg->num_events); return 0; probe_err3: /* Idle the DMAC */ - list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels, + list_for_each_entry_safe(pch, _p, &pl330->ddma.channels, chan.device_node) { /* Remove the channel */ @@ -2933,27 +2851,23 @@ probe_err3: pl330_free_chan_resources(&pch->chan); } probe_err2: - pl330_del(pi); + pl330_del(pl330); return ret; } static int pl330_remove(struct amba_device *adev) { - struct dma_pl330_dmac *pdmac = amba_get_drvdata(adev); + struct pl330_dmac *pl330 = amba_get_drvdata(adev); struct dma_pl330_chan *pch, *_p; - struct pl330_info *pi; - - if (!pdmac) - return 0; if (adev->dev.of_node) of_dma_controller_free(adev->dev.of_node); - dma_async_device_unregister(&pdmac->ddma); + dma_async_device_unregister(&pl330->ddma); /* Idle the DMAC */ - list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels, + list_for_each_entry_safe(pch, _p, &pl330->ddma.channels, chan.device_node) { /* Remove the channel */ @@ -2964,9 +2878,7 @@ static int pl330_remove(struct amba_device *adev) pl330_free_chan_resources(&pch->chan); } - pi = &pdmac->pif; - - pl330_del(pi); + pl330_del(pl330); return 0; } -- cgit v1.2.3 From 9dc5a315fe515e92f40c387ae15f8b760568834e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:30 +0200 Subject: dmaengine: pl330: Embed pl330_req directly into dma_pl330_desc The pl330_req struct is embedded into the dma_pl330_desc struct. But half of the pl330_req struct are pointers to other fields of the dma_pl330_desc struct it is embedded to. By directly embedding the fields from the pl330_req struct into the dma_pl330_desc struct and reworking the code to work with the dma_pl330_desc struct those pointers can be eliminated. This slightly simplifies the code. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 159 +++++++++++++++++++++++----------------------------- 1 file changed, 69 insertions(+), 90 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index e5fe9c764f53..b31c6c380158 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -332,19 +332,6 @@ enum pl330_op_err { PL330_ERR_FAIL, }; -/* A request defining Scatter-Gather List ending with NULL xfer. */ -struct pl330_req { - enum dma_transfer_direction rqtype; - /* Index of peripheral for the xfer. */ - unsigned peri:5; - /* If NULL, req will be done at last set parameters. */ - struct pl330_reqcfg *cfg; - /* Pointer to first xfer in the request. */ - struct pl330_xfer *x; - /* Hook to attach to DMAC's list of reqs with due callback */ - struct list_head rqd; -}; - enum pl330_chan_op { /* Start the channel */ PL330_OP_START, @@ -354,12 +341,6 @@ enum pl330_chan_op { PL330_OP_FLUSH, }; -struct _xfer_spec { - u32 ccr; - struct pl330_req *r; - struct pl330_xfer *x; -}; - enum dmamov_dst { SAR = 0, CCR, @@ -377,10 +358,12 @@ enum pl330_cond { ALWAYS, }; +struct dma_pl330_desc; + struct _pl330_req { u32 mc_bus; void *mc_cpu; - struct pl330_req *r; + struct dma_pl330_desc *desc; }; /* ToBeDone for tasklet */ @@ -526,12 +509,22 @@ struct dma_pl330_desc { struct pl330_xfer px; struct pl330_reqcfg rqcfg; - struct pl330_req req; enum desc_status status; /* The channel which currently holds this desc */ struct dma_pl330_chan *pchan; + + enum dma_transfer_direction rqtype; + /* Index of peripheral for the xfer. */ + unsigned peri:5; + /* Hook to attach to DMAC's list of reqs with due callback */ + struct list_head rqd; +}; + +struct _xfer_spec { + u32 ccr; + struct dma_pl330_desc *desc; }; static inline bool _queue_empty(struct pl330_thread *thrd) @@ -1055,7 +1048,7 @@ static bool _trigger(struct pl330_thread *thrd) { void __iomem *regs = thrd->dmac->base; struct _pl330_req *req; - struct pl330_req *r; + struct dma_pl330_desc *desc; struct _arg_GO go; unsigned ns; u8 insn[6] = {0, 0, 0, 0, 0, 0}; @@ -1077,17 +1070,12 @@ static bool _trigger(struct pl330_thread *thrd) } /* Return if no request */ - if (!req || !req->r) + if (!req || !req->desc) return true; - r = req->r; + desc = req->desc; - if (r->cfg) - ns = r->cfg->nonsecure ? 1 : 0; - else if (readl(regs + CS(thrd->id)) & CS_CNS) - ns = 1; - else - ns = 0; + ns = desc->rqcfg.nonsecure ? 1 : 0; /* See 'Abort Sources' point-4 at Page 2-25 */ if (_manager_ns(thrd) && !ns) @@ -1147,7 +1135,7 @@ static inline int _ldst_memtomem(unsigned dry_run, u8 buf[], const struct _xfer_spec *pxs, int cyc) { int off = 0; - struct pl330_config *pcfg = pxs->r->cfg->pcfg; + struct pl330_config *pcfg = pxs->desc->rqcfg.pcfg; /* check lock-up free version */ if (get_revision(pcfg->periph_id) >= PERIPH_REV_R1P0) { @@ -1173,10 +1161,10 @@ static inline int _ldst_devtomem(unsigned dry_run, u8 buf[], int off = 0; while (cyc--) { - off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri); - off += _emit_LDP(dry_run, &buf[off], SINGLE, pxs->r->peri); + off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->desc->peri); + off += _emit_LDP(dry_run, &buf[off], SINGLE, pxs->desc->peri); off += _emit_ST(dry_run, &buf[off], ALWAYS); - off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri); + off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri); } return off; @@ -1188,10 +1176,10 @@ static inline int _ldst_memtodev(unsigned dry_run, u8 buf[], int off = 0; while (cyc--) { - off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri); + off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->desc->peri); off += _emit_LD(dry_run, &buf[off], ALWAYS); - off += _emit_STP(dry_run, &buf[off], SINGLE, pxs->r->peri); - off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri); + off += _emit_STP(dry_run, &buf[off], SINGLE, pxs->desc->peri); + off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri); } return off; @@ -1202,7 +1190,7 @@ static int _bursts(unsigned dry_run, u8 buf[], { int off = 0; - switch (pxs->r->rqtype) { + switch (pxs->desc->rqtype) { case DMA_MEM_TO_DEV: off += _ldst_memtodev(dry_run, &buf[off], pxs, cyc); break; @@ -1302,7 +1290,7 @@ static inline int _loop(unsigned dry_run, u8 buf[], static inline int _setup_loops(unsigned dry_run, u8 buf[], const struct _xfer_spec *pxs) { - struct pl330_xfer *x = pxs->x; + struct pl330_xfer *x = &pxs->desc->px; u32 ccr = pxs->ccr; unsigned long c, bursts = BYTE_TO_BURST(x->bytes, ccr); int off = 0; @@ -1319,7 +1307,7 @@ static inline int _setup_loops(unsigned dry_run, u8 buf[], static inline int _setup_xfer(unsigned dry_run, u8 buf[], const struct _xfer_spec *pxs) { - struct pl330_xfer *x = pxs->x; + struct pl330_xfer *x = &pxs->desc->px; int off = 0; /* DMAMOV SAR, x->src_addr */ @@ -1350,12 +1338,11 @@ static int _setup_req(unsigned dry_run, struct pl330_thread *thrd, /* DMAMOV CCR, ccr */ off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr); - x = pxs->r->x; + x = &pxs->desc->px; /* Error if xfer length is not aligned at burst size */ if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr))) return -EINVAL; - pxs->x = x; off += _setup_xfer(dry_run, &buf[off], pxs); /* DMASEV peripheral/event */ @@ -1403,7 +1390,8 @@ static inline u32 _prepare_ccr(const struct pl330_reqcfg *rqc) * Client is not notified after each xfer unit, just once after all * xfer units are done or some error occurs. */ -static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) +static int pl330_submit_req(struct pl330_thread *thrd, + struct dma_pl330_desc *desc) { struct pl330_dmac *pl330 = thrd->dmac; struct _xfer_spec xs; @@ -1414,7 +1402,7 @@ static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) int ret = 0; /* No Req or Unacquired Channel or DMAC */ - if (!r || !thrd || thrd->free) + if (!desc || !thrd || thrd->free) return -EINVAL; regs = thrd->dmac->base; @@ -1427,10 +1415,11 @@ static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) } /* If request for non-existing peripheral */ - if (r->rqtype != DMA_MEM_TO_MEM && r->peri >= pl330->pcfg.num_peri) { + if (desc->rqtype != DMA_MEM_TO_MEM && + desc->peri >= pl330->pcfg.num_peri) { dev_info(thrd->dmac->ddma.dev, "%s:%d Invalid peripheral(%u)!\n", - __func__, __LINE__, r->peri); + __func__, __LINE__, desc->peri); return -EINVAL; } @@ -1441,24 +1430,18 @@ static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) goto xfer_exit; } + /* Prefer Secure Channel */ + if (!_manager_ns(thrd)) + desc->rqcfg.nonsecure = 0; + else + desc->rqcfg.nonsecure = 1; - /* Use last settings, if not provided */ - if (r->cfg) { - /* Prefer Secure Channel */ - if (!_manager_ns(thrd)) - r->cfg->nonsecure = 0; - else - r->cfg->nonsecure = 1; - - ccr = _prepare_ccr(r->cfg); - } else { - ccr = readl(regs + CC(thrd->id)); - } + ccr = _prepare_ccr(&desc->rqcfg); idx = IS_FREE(&thrd->req[0]) ? 0 : 1; xs.ccr = ccr; - xs.r = r; + xs.desc = desc; /* First dry run to check if req is acceptable */ ret = _setup_req(1, thrd, idx, &xs); @@ -1474,7 +1457,7 @@ static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_req *r) /* Hook the request */ thrd->lstenq = idx; - thrd->req[idx].r = r; + thrd->req[idx].desc = desc; _setup_req(0, thrd, idx, &xs); ret = 0; @@ -1485,9 +1468,8 @@ xfer_exit: return ret; } -static void dma_pl330_rqcb(struct pl330_req *req, enum pl330_op_err err) +static void dma_pl330_rqcb(struct dma_pl330_desc *desc, enum pl330_op_err err) { - struct dma_pl330_desc *desc = container_of(req, struct dma_pl330_desc, req); struct dma_pl330_chan *pch = desc->pchan; unsigned long flags; @@ -1544,12 +1526,12 @@ static void pl330_dotask(unsigned long data) err = PL330_ERR_ABORT; spin_unlock_irqrestore(&pl330->lock, flags); - dma_pl330_rqcb(thrd->req[1 - thrd->lstenq].r, err); - dma_pl330_rqcb(thrd->req[thrd->lstenq].r, err); + dma_pl330_rqcb(thrd->req[1 - thrd->lstenq].desc, err); + dma_pl330_rqcb(thrd->req[thrd->lstenq].desc, err); spin_lock_irqsave(&pl330->lock, flags); - thrd->req[0].r = NULL; - thrd->req[1].r = NULL; + thrd->req[0].desc = NULL; + thrd->req[1].desc = NULL; mark_free(thrd, 0); mark_free(thrd, 1); @@ -1566,7 +1548,7 @@ static void pl330_dotask(unsigned long data) /* Returns 1 if state was updated, 0 otherwise */ static int pl330_update(struct pl330_dmac *pl330) { - struct pl330_req *rqdone, *tmp; + struct dma_pl330_desc *descdone, *tmp; unsigned long flags; void __iomem *regs; u32 val; @@ -1630,8 +1612,8 @@ static int pl330_update(struct pl330_dmac *pl330) continue; /* Detach the req */ - rqdone = thrd->req[active].r; - thrd->req[active].r = NULL; + descdone = thrd->req[active].desc; + thrd->req[active].desc = NULL; mark_free(thrd, active); @@ -1639,16 +1621,15 @@ static int pl330_update(struct pl330_dmac *pl330) _start(thrd); /* For now, just make a list of callbacks to be done */ - list_add_tail(&rqdone->rqd, &pl330->req_done); + list_add_tail(&descdone->rqd, &pl330->req_done); } } /* Now that we are in no hurry, do the callbacks */ - list_for_each_entry_safe(rqdone, tmp, &pl330->req_done, rqd) { - list_del(&rqdone->rqd); - + list_for_each_entry_safe(descdone, tmp, &pl330->req_done, rqd) { + list_del(&descdone->rqd); spin_unlock_irqrestore(&pl330->lock, flags); - dma_pl330_rqcb(rqdone, PL330_ERR_NONE); + dma_pl330_rqcb(descdone, PL330_ERR_NONE); spin_lock_irqsave(&pl330->lock, flags); } @@ -1684,8 +1665,8 @@ static int pl330_chan_ctrl(struct pl330_thread *thrd, enum pl330_chan_op op) /* Make sure the channel is stopped */ _stop(thrd); - thrd->req[0].r = NULL; - thrd->req[1].r = NULL; + thrd->req[0].desc = NULL; + thrd->req[1].desc = NULL; mark_free(thrd, 0); mark_free(thrd, 1); break; @@ -1698,7 +1679,7 @@ static int pl330_chan_ctrl(struct pl330_thread *thrd, enum pl330_chan_op op) if (active == -1) break; - thrd->req[active].r = NULL; + thrd->req[active].desc = NULL; mark_free(thrd, active); /* Start the next */ @@ -1759,9 +1740,9 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) if (thrd->ev >= 0) { thrd->free = false; thrd->lstenq = 1; - thrd->req[0].r = NULL; + thrd->req[0].desc = NULL; mark_free(thrd, 0); - thrd->req[1].r = NULL; + thrd->req[1].desc = NULL; mark_free(thrd, 1); break; } @@ -1795,8 +1776,8 @@ static void pl330_release_channel(struct pl330_thread *thrd) _stop(thrd); - dma_pl330_rqcb(thrd->req[1 - thrd->lstenq].r, PL330_ERR_ABORT); - dma_pl330_rqcb(thrd->req[thrd->lstenq].r, PL330_ERR_ABORT); + dma_pl330_rqcb(thrd->req[1 - thrd->lstenq].desc, PL330_ERR_ABORT); + dma_pl330_rqcb(thrd->req[thrd->lstenq].desc, PL330_ERR_ABORT); pl330 = thrd->dmac; @@ -1859,14 +1840,14 @@ static inline void _reset_thread(struct pl330_thread *thrd) + (thrd->id * pl330->mcbufsz); thrd->req[0].mc_bus = pl330->mcode_bus + (thrd->id * pl330->mcbufsz); - thrd->req[0].r = NULL; + thrd->req[0].desc = NULL; mark_free(thrd, 0); thrd->req[1].mc_cpu = thrd->req[0].mc_cpu + pl330->mcbufsz / 2; thrd->req[1].mc_bus = thrd->req[0].mc_bus + pl330->mcbufsz / 2; - thrd->req[1].r = NULL; + thrd->req[1].desc = NULL; mark_free(thrd, 1); } @@ -2041,7 +2022,7 @@ static inline void fill_queue(struct dma_pl330_chan *pch) if (desc->status == BUSY) continue; - ret = pl330_submit_req(pch->thread, &desc->req); + ret = pl330_submit_req(pch->thread, desc); if (!ret) { desc->status = BUSY; } else if (ret == -EAGAIN) { @@ -2301,11 +2282,9 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx) static inline void _init_desc(struct dma_pl330_desc *desc) { - desc->req.x = &desc->px; desc->rqcfg.swap = SWAP_NO; desc->rqcfg.scctl = CCTRL0; desc->rqcfg.dcctl = CCTRL0; - desc->req.cfg = &desc->rqcfg; desc->txd.tx_submit = pl330_tx_submit; INIT_LIST_HEAD(&desc->node); @@ -2384,7 +2363,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) desc->txd.cookie = 0; async_tx_ack(&desc->txd); - desc->req.peri = peri_id ? pch->chan.chan_id : 0; + desc->peri = peri_id ? pch->chan.chan_id : 0; desc->rqcfg.pcfg = &pch->dmac->pcfg; dma_async_tx_descriptor_init(&desc->txd, &pch->chan); @@ -2513,7 +2492,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( break; } - desc->req.rqtype = direction; + desc->rqtype = direction; desc->rqcfg.brst_size = pch->burst_sz; desc->rqcfg.brst_len = 1; fill_px(&desc->px, dst, src, period_len); @@ -2553,7 +2532,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 1; - desc->req.rqtype = DMA_MEM_TO_MEM; + desc->rqtype = DMA_MEM_TO_MEM; /* Select max possible burst size */ burst = pl330->pcfg.data_bus_width / 8; @@ -2648,7 +2627,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc->rqcfg.brst_size = pch->burst_sz; desc->rqcfg.brst_len = 1; - desc->req.rqtype = direction; + desc->rqtype = direction; } /* Return the last desc in the chain */ -- cgit v1.2.3 From 8ed30a14265fc2ebace02ea321c463facedfac17 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:31 +0200 Subject: dmaengine: pl330: Simplify marking a request as unused Instead of storing a special instruction in the command buffer to mark a request as currently unused just set the descriptor field to NULL. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 51 +++++++++++++-------------------------------------- 1 file changed, 13 insertions(+), 38 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index b31c6c380158..105e33e3bb33 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -245,9 +245,6 @@ enum pl330_byteswap { */ #define MCODE_BUFF_PER_REQ 256 -/* If the _pl330_req is available to the client */ -#define IS_FREE(req) (*((u8 *)((req)->mc_cpu)) == CMD_DMAEND) - /* Use this _only_ to wait on transient states */ #define UNTIL(t, s) while (!(_state(t) & (s))) cpu_relax(); @@ -529,14 +526,12 @@ struct _xfer_spec { static inline bool _queue_empty(struct pl330_thread *thrd) { - return (IS_FREE(&thrd->req[0]) && IS_FREE(&thrd->req[1])) - ? true : false; + return thrd->req[0].desc == NULL && thrd->req[1].desc == NULL; } static inline bool _queue_full(struct pl330_thread *thrd) { - return (IS_FREE(&thrd->req[0]) || IS_FREE(&thrd->req[1])) - ? false : true; + return thrd->req[0].desc != NULL && thrd->req[1].desc != NULL; } static inline bool is_manager(struct pl330_thread *thrd) @@ -948,21 +943,6 @@ static inline void _execute_DBGINSN(struct pl330_thread *thrd, writel(0, regs + DBGCMD); } -/* - * Mark a _pl330_req as free. - * We do it by writing DMAEND as the first instruction - * because no valid request is going to have DMAEND as - * its first instruction to execute. - */ -static void mark_free(struct pl330_thread *thrd, int idx) -{ - struct _pl330_req *req = &thrd->req[idx]; - - _emit_END(0, req->mc_cpu); - - thrd->req_running = -1; -} - static inline u32 _state(struct pl330_thread *thrd) { void __iomem *regs = thrd->dmac->base; @@ -1059,18 +1039,18 @@ static bool _trigger(struct pl330_thread *thrd) return true; idx = 1 - thrd->lstenq; - if (!IS_FREE(&thrd->req[idx])) + if (thrd->req[idx].desc != NULL) { req = &thrd->req[idx]; - else { + } else { idx = thrd->lstenq; - if (!IS_FREE(&thrd->req[idx])) + if (thrd->req[idx].desc != NULL) req = &thrd->req[idx]; else req = NULL; } /* Return if no request */ - if (!req || !req->desc) + if (!req) return true; desc = req->desc; @@ -1438,7 +1418,7 @@ static int pl330_submit_req(struct pl330_thread *thrd, ccr = _prepare_ccr(&desc->rqcfg); - idx = IS_FREE(&thrd->req[0]) ? 0 : 1; + idx = thrd->req[0].desc == NULL ? 0 : 1; xs.ccr = ccr; xs.desc = desc; @@ -1532,8 +1512,7 @@ static void pl330_dotask(unsigned long data) thrd->req[0].desc = NULL; thrd->req[1].desc = NULL; - mark_free(thrd, 0); - mark_free(thrd, 1); + thrd->req_running = -1; /* Clear the reset flag */ pl330->dmac_tbd.reset_chan &= ~(1 << i); @@ -1615,8 +1594,6 @@ static int pl330_update(struct pl330_dmac *pl330) descdone = thrd->req[active].desc; thrd->req[active].desc = NULL; - mark_free(thrd, active); - /* Get going again ASAP */ _start(thrd); @@ -1667,8 +1644,7 @@ static int pl330_chan_ctrl(struct pl330_thread *thrd, enum pl330_chan_op op) thrd->req[0].desc = NULL; thrd->req[1].desc = NULL; - mark_free(thrd, 0); - mark_free(thrd, 1); + thrd->req_running = -1; break; case PL330_OP_ABORT: @@ -1680,7 +1656,7 @@ static int pl330_chan_ctrl(struct pl330_thread *thrd, enum pl330_chan_op op) break; thrd->req[active].desc = NULL; - mark_free(thrd, active); + thrd->req_running = -1; /* Start the next */ case PL330_OP_START: @@ -1741,9 +1717,8 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) thrd->free = false; thrd->lstenq = 1; thrd->req[0].desc = NULL; - mark_free(thrd, 0); thrd->req[1].desc = NULL; - mark_free(thrd, 1); + thrd->req_running = -1; break; } } @@ -1841,14 +1816,14 @@ static inline void _reset_thread(struct pl330_thread *thrd) thrd->req[0].mc_bus = pl330->mcode_bus + (thrd->id * pl330->mcbufsz); thrd->req[0].desc = NULL; - mark_free(thrd, 0); thrd->req[1].mc_cpu = thrd->req[0].mc_cpu + pl330->mcbufsz / 2; thrd->req[1].mc_bus = thrd->req[0].mc_bus + pl330->mcbufsz / 2; thrd->req[1].desc = NULL; - mark_free(thrd, 1); + + thrd->req_running = -1; } static int dmac_alloc_threads(struct pl330_dmac *pl330) -- cgit v1.2.3 From c26939e5204c533b9348cdd0b4155758f9276df1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 6 Jul 2014 20:32:32 +0200 Subject: dmaengine: pl330: Remove pl330_chan_ctrl() The pl330_chan_ctrl() function has 3 internal code paths which, except for the locking, do not share any code outside of their sections. One code path is never exercised and can be removed. The other two are mostly just forwards to the _start() and _stop() calls. This patch modifies the code to instead of going via pl330_chan_ctrl() to call _start() and _stop() directly. This allows to completely remove pl330_chan_ctrl(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 71 ++++++++--------------------------------------------- 1 file changed, 10 insertions(+), 61 deletions(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 105e33e3bb33..bc5878a5c09e 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -329,15 +329,6 @@ enum pl330_op_err { PL330_ERR_FAIL, }; -enum pl330_chan_op { - /* Start the channel */ - PL330_OP_START, - /* Abort the active xfer */ - PL330_OP_ABORT, - /* Stop xfer and flush queue */ - PL330_OP_FLUSH, -}; - enum dmamov_dst { SAR = 0, CCR, @@ -1623,55 +1614,6 @@ updt_exit: return ret; } -static int pl330_chan_ctrl(struct pl330_thread *thrd, enum pl330_chan_op op) -{ - struct pl330_dmac *pl330; - unsigned long flags; - int ret = 0, active; - - if (!thrd || thrd->free || thrd->dmac->state == DYING) - return -EINVAL; - - pl330 = thrd->dmac; - active = thrd->req_running; - - spin_lock_irqsave(&pl330->lock, flags); - - switch (op) { - case PL330_OP_FLUSH: - /* Make sure the channel is stopped */ - _stop(thrd); - - thrd->req[0].desc = NULL; - thrd->req[1].desc = NULL; - thrd->req_running = -1; - break; - - case PL330_OP_ABORT: - /* Make sure the channel is stopped */ - _stop(thrd); - - /* ABORT is only for the active req */ - if (active == -1) - break; - - thrd->req[active].desc = NULL; - thrd->req_running = -1; - - /* Start the next */ - case PL330_OP_START: - if ((active == -1) && !_start(thrd)) - ret = -EIO; - break; - - default: - ret = -EINVAL; - } - - spin_unlock_irqrestore(&pl330->lock, flags); - return ret; -} - /* Reserve an event */ static inline int _alloc_event(struct pl330_thread *thrd) { @@ -2033,7 +1975,9 @@ static void pl330_tasklet(unsigned long data) fill_queue(pch); /* Make sure the PL330 Channel thread is active */ - pl330_chan_ctrl(pch->thread, PL330_OP_START); + spin_lock(&pch->thread->dmac->lock); + _start(pch->thread); + spin_unlock(&pch->thread->dmac->lock); while (!list_empty(&pch->completed_list)) { dma_async_tx_callback callback; @@ -2133,8 +2077,13 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned case DMA_TERMINATE_ALL: spin_lock_irqsave(&pch->lock, flags); - /* FLUSH the PL330 Channel thread */ - pl330_chan_ctrl(pch->thread, PL330_OP_FLUSH); + spin_lock(&pl330->lock); + _stop(pch->thread); + spin_unlock(&pl330->lock); + + pch->thread->req[0].desc = NULL; + pch->thread->req[1].desc = NULL; + pch->thread->req_running = -1; /* Mark all desc done */ list_for_each_entry(desc, &pch->submitted_list, node) { -- cgit v1.2.3 From b1e51d771fbc9fec15785760a2f725040a0fe671 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 19 Jul 2014 03:21:47 +0200 Subject: dmaengine: pl330: Check if the DMA descriptor is NULL Commit 6079d38 ("dmaengine: pl330: Remove useless xfer_cb indirection") removed the __callback() function which created an unnecessary level of indirection to execute the tranfer callback .xfer_cb Unfortunately the commit also changed the semantics slightly since that function used to check if the request was not NULL before attempting to execute the callback function. Not checking this could lead to a kernel NULL pointer dereference error. Signed-off-by: Javier Martinez Canillas Acked-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index bc5878a5c09e..a55d75498098 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1441,9 +1441,14 @@ xfer_exit: static void dma_pl330_rqcb(struct dma_pl330_desc *desc, enum pl330_op_err err) { - struct dma_pl330_chan *pch = desc->pchan; + struct dma_pl330_chan *pch; unsigned long flags; + if (!desc) + return; + + pch = desc->pchan; + /* If desc aborted */ if (!pch) return; -- cgit v1.2.3 From 31c1e5a1350ae8d1bc2018f5de8264266d9773e1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 1 Aug 2014 12:20:10 +0200 Subject: dmaengine: Remove the context argument to the prep_dma_cyclic operation The argument is always set to NULL and never used. Remove it. Signed-off-by: Laurent Pinchart Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/dma/pl330.c') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index a55d75498098..d5149aacd2fe 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2362,7 +2362,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t len, size_t period_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) + unsigned long flags) { struct dma_pl330_desc *desc = NULL, *first = NULL; struct dma_pl330_chan *pch = to_pchan(chan); -- cgit v1.2.3