diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dma/Kconfig | 2 | ||||
-rw-r--r-- | drivers/dma/at_hdmac_regs.h | 2 | ||||
-rw-r--r-- | drivers/dma/bcm-sba-raid.c | 117 | ||||
-rw-r--r-- | drivers/dma/coh901318.c | 6 | ||||
-rw-r--r-- | drivers/dma/dma-axi-dmac.c | 75 | ||||
-rw-r--r-- | drivers/dma/dmatest.c | 1 | ||||
-rw-r--r-- | drivers/dma/pch_dma.c | 12 |
7 files changed, 104 insertions, 111 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index fadc4d8783bd..48cf8df7255f 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -115,7 +115,7 @@ config BCM_SBA_RAID select DMA_ENGINE_RAID select ASYNC_TX_DISABLE_XOR_VAL_DMA select ASYNC_TX_DISABLE_PQ_VAL_DMA - default ARCH_BCM_IPROC + default m if ARCH_BCM_IPROC help Enable support for Broadcom SBA RAID Engine. The SBA RAID engine is available on most of the Broadcom iProc SoCs. It diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 7f58f06157f6..ef3f227ce3e6 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -385,7 +385,7 @@ static void vdbg_dump_regs(struct at_dma_chan *atchan) {} static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli) { dev_crit(chan2dev(&atchan->chan_common), - " desc: s%pad d%pad ctrl0x%x:0x%x l0x%pad\n", + "desc: s%pad d%pad ctrl0x%x:0x%x l%pad\n", &lli->saddr, &lli->daddr, lli->ctrla, lli->ctrlb, &lli->dscr); } diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c index 6c2c44724637..3956a018bf5a 100644 --- a/drivers/dma/bcm-sba-raid.c +++ b/drivers/dma/bcm-sba-raid.c @@ -1,9 +1,14 @@ /* * Copyright (C) 2017 Broadcom * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ /* @@ -25,11 +30,8 @@ * * The Broadcom SBA RAID driver does not require any register programming * except submitting request to SBA hardware device via mailbox channels. - * This driver implements a DMA device with one DMA channel using a set - * of mailbox channels provided by Broadcom SoC specific ring manager - * driver. To exploit parallelism (as described above), all DMA request - * coming to SBA RAID DMA channel are broken down to smaller requests - * and submitted to multiple mailbox channels in round-robin fashion. + * This driver implements a DMA device with one DMA channel using a single + * mailbox channel provided by Broadcom SoC specific ring manager driver. * For having more SBA DMA channels, we can create more SBA device nodes * in Broadcom SoC specific DTS based on number of hardware rings supported * by Broadcom SoC ring manager. @@ -85,6 +87,7 @@ #define SBA_CMD_GALOIS 0xe #define SBA_MAX_REQ_PER_MBOX_CHANNEL 8192 +#define SBA_MAX_MSG_SEND_PER_MBOX_CHANNEL 8 /* Driver helper macros */ #define to_sba_request(tx) \ @@ -142,9 +145,7 @@ struct sba_device { u32 max_cmds_pool_size; /* Maibox client and Mailbox channels */ struct mbox_client client; - int mchans_count; - atomic_t mchans_current; - struct mbox_chan **mchans; + struct mbox_chan *mchan; struct device *mbox_dev; /* DMA device and DMA channel */ struct dma_device dma_dev; @@ -200,14 +201,6 @@ static inline u32 __pure sba_cmd_pq_c_mdata(u32 d, u32 b1, u32 b0) /* ====== General helper routines ===== */ -static void sba_peek_mchans(struct sba_device *sba) -{ - int mchan_idx; - - for (mchan_idx = 0; mchan_idx < sba->mchans_count; mchan_idx++) - mbox_client_peek_data(sba->mchans[mchan_idx]); -} - static struct sba_request *sba_alloc_request(struct sba_device *sba) { bool found = false; @@ -231,7 +224,7 @@ static struct sba_request *sba_alloc_request(struct sba_device *sba) * would have completed which will create more * room for new requests. */ - sba_peek_mchans(sba); + mbox_client_peek_data(sba->mchan); return NULL; } @@ -369,15 +362,11 @@ static void sba_cleanup_pending_requests(struct sba_device *sba) static int sba_send_mbox_request(struct sba_device *sba, struct sba_request *req) { - int mchans_idx, ret = 0; - - /* Select mailbox channel in round-robin fashion */ - mchans_idx = atomic_inc_return(&sba->mchans_current); - mchans_idx = mchans_idx % sba->mchans_count; + int ret = 0; /* Send message for the request */ req->msg.error = 0; - ret = mbox_send_message(sba->mchans[mchans_idx], &req->msg); + ret = mbox_send_message(sba->mchan, &req->msg); if (ret < 0) { dev_err(sba->dev, "send message failed with error %d", ret); return ret; @@ -390,7 +379,7 @@ static int sba_send_mbox_request(struct sba_device *sba, } /* Signal txdone for mailbox channel */ - mbox_client_txdone(sba->mchans[mchans_idx], ret); + mbox_client_txdone(sba->mchan, ret); return ret; } @@ -402,13 +391,8 @@ static void _sba_process_pending_requests(struct sba_device *sba) u32 count; struct sba_request *req; - /* - * Process few pending requests - * - * For now, we process (<number_of_mailbox_channels> * 8) - * number of requests at a time. - */ - count = sba->mchans_count * 8; + /* Process few pending requests */ + count = SBA_MAX_MSG_SEND_PER_MBOX_CHANNEL; while (!list_empty(&sba->reqs_pending_list) && count) { /* Get the first pending request */ req = list_first_entry(&sba->reqs_pending_list, @@ -442,7 +426,9 @@ static void sba_process_received_request(struct sba_device *sba, WARN_ON(tx->cookie < 0); if (tx->cookie > 0) { + spin_lock_irqsave(&sba->reqs_lock, flags); dma_cookie_complete(tx); + spin_unlock_irqrestore(&sba->reqs_lock, flags); dmaengine_desc_get_callback_invoke(tx, NULL); dma_descriptor_unmap(tx); tx->callback = NULL; @@ -570,7 +556,7 @@ static enum dma_status sba_tx_status(struct dma_chan *dchan, if (ret == DMA_COMPLETE) return ret; - sba_peek_mchans(sba); + mbox_client_peek_data(sba->mchan); return dma_cookie_status(dchan, cookie, txstate); } @@ -1637,7 +1623,7 @@ static int sba_async_register(struct sba_device *sba) static int sba_probe(struct platform_device *pdev) { - int i, ret = 0, mchans_count; + int ret = 0; struct sba_device *sba; struct platform_device *mbox_pdev; struct of_phandle_args args; @@ -1650,12 +1636,11 @@ static int sba_probe(struct platform_device *pdev) sba->dev = &pdev->dev; platform_set_drvdata(pdev, sba); - /* Number of channels equals number of mailbox channels */ + /* Number of mailbox channels should be atleast 1 */ ret = of_count_phandle_with_args(pdev->dev.of_node, "mboxes", "#mbox-cells"); if (ret <= 0) return -ENODEV; - mchans_count = ret; /* Determine SBA version from DT compatible string */ if (of_device_is_compatible(sba->dev->of_node, "brcm,iproc-sba")) @@ -1688,7 +1673,7 @@ static int sba_probe(struct platform_device *pdev) default: return -EINVAL; } - sba->max_req = SBA_MAX_REQ_PER_MBOX_CHANNEL * mchans_count; + sba->max_req = SBA_MAX_REQ_PER_MBOX_CHANNEL; sba->max_cmd_per_req = sba->max_pq_srcs + 3; sba->max_xor_srcs = sba->max_cmd_per_req - 1; sba->max_resp_pool_size = sba->max_req * sba->hw_resp_size; @@ -1702,55 +1687,30 @@ static int sba_probe(struct platform_device *pdev) sba->client.knows_txdone = true; sba->client.tx_tout = 0; - /* Allocate mailbox channel array */ - sba->mchans = devm_kcalloc(&pdev->dev, mchans_count, - sizeof(*sba->mchans), GFP_KERNEL); - if (!sba->mchans) - return -ENOMEM; - - /* Request mailbox channels */ - sba->mchans_count = 0; - for (i = 0; i < mchans_count; i++) { - sba->mchans[i] = mbox_request_channel(&sba->client, i); - if (IS_ERR(sba->mchans[i])) { - ret = PTR_ERR(sba->mchans[i]); - goto fail_free_mchans; - } - sba->mchans_count++; + /* Request mailbox channel */ + sba->mchan = mbox_request_channel(&sba->client, 0); + if (IS_ERR(sba->mchan)) { + ret = PTR_ERR(sba->mchan); + goto fail_free_mchan; } - atomic_set(&sba->mchans_current, 0); /* Find-out underlying mailbox device */ ret = of_parse_phandle_with_args(pdev->dev.of_node, "mboxes", "#mbox-cells", 0, &args); if (ret) - goto fail_free_mchans; + goto fail_free_mchan; mbox_pdev = of_find_device_by_node(args.np); of_node_put(args.np); if (!mbox_pdev) { ret = -ENODEV; - goto fail_free_mchans; + goto fail_free_mchan; } sba->mbox_dev = &mbox_pdev->dev; - /* All mailbox channels should be of same ring manager device */ - for (i = 1; i < mchans_count; i++) { - ret = of_parse_phandle_with_args(pdev->dev.of_node, - "mboxes", "#mbox-cells", i, &args); - if (ret) - goto fail_free_mchans; - mbox_pdev = of_find_device_by_node(args.np); - of_node_put(args.np); - if (sba->mbox_dev != &mbox_pdev->dev) { - ret = -EINVAL; - goto fail_free_mchans; - } - } - /* Prealloc channel resource */ ret = sba_prealloc_channel_resources(sba); if (ret) - goto fail_free_mchans; + goto fail_free_mchan; /* Check availability of debugfs */ if (!debugfs_initialized()) @@ -1777,24 +1737,22 @@ skip_debugfs: goto fail_free_resources; /* Print device info */ - dev_info(sba->dev, "%s using SBAv%d and %d mailbox channels", + dev_info(sba->dev, "%s using SBAv%d mailbox channel from %s", dma_chan_name(&sba->dma_chan), sba->ver+1, - sba->mchans_count); + dev_name(sba->mbox_dev)); return 0; fail_free_resources: debugfs_remove_recursive(sba->root); sba_freeup_channel_resources(sba); -fail_free_mchans: - for (i = 0; i < sba->mchans_count; i++) - mbox_free_channel(sba->mchans[i]); +fail_free_mchan: + mbox_free_channel(sba->mchan); return ret; } static int sba_remove(struct platform_device *pdev) { - int i; struct sba_device *sba = platform_get_drvdata(pdev); dma_async_device_unregister(&sba->dma_dev); @@ -1803,8 +1761,7 @@ static int sba_remove(struct platform_device *pdev) sba_freeup_channel_resources(sba); - for (i = 0; i < sba->mchans_count; i++) - mbox_free_channel(sba->mchans[i]); + mbox_free_channel(sba->mchan); return 0; } diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 74794c9859f6..da74fd74636b 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -1319,8 +1319,8 @@ static void coh901318_list_print(struct coh901318_chan *cohc, int i = 0; while (l) { - dev_vdbg(COHC_2_DEV(cohc), "i %d, lli %p, ctrl 0x%x, src 0x%pad" - ", dst 0x%pad, link 0x%pad virt_link_addr 0x%p\n", + dev_vdbg(COHC_2_DEV(cohc), "i %d, lli %p, ctrl 0x%x, src %pad" + ", dst %pad, link %pad virt_link_addr 0x%p\n", i, l, l->control, &l->src_addr, &l->dst_addr, &l->link_addr, l->virt_link_addr); i++; @@ -2231,7 +2231,7 @@ coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, spin_lock_irqsave(&cohc->lock, flg); dev_vdbg(COHC_2_DEV(cohc), - "[%s] channel %d src 0x%pad dest 0x%pad size %zu\n", + "[%s] channel %d src %pad dest %pad size %zu\n", __func__, cohc->id, &src, &dest, size); if (flags & DMA_PREP_INTERRUPT) diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index 7f0b9aa15867..2419fe524daa 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -72,6 +72,9 @@ #define AXI_DMAC_FLAG_CYCLIC BIT(0) +/* The maximum ID allocated by the hardware is 31 */ +#define AXI_DMAC_SG_UNUSED 32U + struct axi_dmac_sg { dma_addr_t src_addr; dma_addr_t dest_addr; @@ -80,6 +83,7 @@ struct axi_dmac_sg { unsigned int dest_stride; unsigned int src_stride; unsigned int id; + bool schedule_when_free; }; struct axi_dmac_desc { @@ -200,11 +204,21 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) } sg = &desc->sg[desc->num_submitted]; + /* Already queued in cyclic mode. Wait for it to finish */ + if (sg->id != AXI_DMAC_SG_UNUSED) { + sg->schedule_when_free = true; + return; + } + desc->num_submitted++; - if (desc->num_submitted == desc->num_sgs) - chan->next_desc = NULL; - else + if (desc->num_submitted == desc->num_sgs) { + if (desc->cyclic) + desc->num_submitted = 0; /* Start again */ + else + chan->next_desc = NULL; + } else { chan->next_desc = desc; + } sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); @@ -220,9 +234,11 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) /* * If the hardware supports cyclic transfers and there is no callback to - * call, enable hw cyclic mode to avoid unnecessary interrupts. + * call and only a single segment, enable hw cyclic mode to avoid + * unnecessary interrupts. */ - if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback) + if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback && + desc->num_sgs == 1) flags |= AXI_DMAC_FLAG_CYCLIC; axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, sg->x_len - 1); @@ -237,37 +253,52 @@ static struct axi_dmac_desc *axi_dmac_active_desc(struct axi_dmac_chan *chan) struct axi_dmac_desc, vdesc.node); } -static void axi_dmac_transfer_done(struct axi_dmac_chan *chan, +static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan, unsigned int completed_transfers) { struct axi_dmac_desc *active; struct axi_dmac_sg *sg; + bool start_next = false; active = axi_dmac_active_desc(chan); if (!active) - return; + return false; - if (active->cyclic) { - vchan_cyclic_callback(&active->vdesc); - } else { - do { - sg = &active->sg[active->num_completed]; - if (!(BIT(sg->id) & completed_transfers)) - break; - active->num_completed++; - if (active->num_completed == active->num_sgs) { + do { + sg = &active->sg[active->num_completed]; + if (sg->id == AXI_DMAC_SG_UNUSED) /* Not yet submitted */ + break; + if (!(BIT(sg->id) & completed_transfers)) + break; + active->num_completed++; + sg->id = AXI_DMAC_SG_UNUSED; + if (sg->schedule_when_free) { + sg->schedule_when_free = false; + start_next = true; + } + + if (active->cyclic) + vchan_cyclic_callback(&active->vdesc); + + if (active->num_completed == active->num_sgs) { + if (active->cyclic) { + active->num_completed = 0; /* wrap around */ + } else { list_del(&active->vdesc.node); vchan_cookie_complete(&active->vdesc); active = axi_dmac_active_desc(chan); } - } while (active); - } + } + } while (active); + + return start_next; } static irqreturn_t axi_dmac_interrupt_handler(int irq, void *devid) { struct axi_dmac *dmac = devid; unsigned int pending; + bool start_next = false; pending = axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING); if (!pending) @@ -281,10 +312,10 @@ static irqreturn_t axi_dmac_interrupt_handler(int irq, void *devid) unsigned int completed; completed = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_DONE); - axi_dmac_transfer_done(&dmac->chan, completed); + start_next = axi_dmac_transfer_done(&dmac->chan, completed); } /* Space has become available in the descriptor queue */ - if (pending & AXI_DMAC_IRQ_SOT) + if ((pending & AXI_DMAC_IRQ_SOT) || start_next) axi_dmac_start_transfer(&dmac->chan); spin_unlock(&dmac->chan.vchan.lock); @@ -334,12 +365,16 @@ static void axi_dmac_issue_pending(struct dma_chan *c) static struct axi_dmac_desc *axi_dmac_alloc_desc(unsigned int num_sgs) { struct axi_dmac_desc *desc; + unsigned int i; desc = kzalloc(sizeof(struct axi_dmac_desc) + sizeof(struct axi_dmac_sg) * num_sgs, GFP_NOWAIT); if (!desc) return NULL; + for (i = 0; i < num_sgs; i++) + desc->sg[i].id = AXI_DMAC_SG_UNUSED; + desc->num_sgs = num_sgs; return desc; diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 34ff53290b03..47edc7fbf91f 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -702,6 +702,7 @@ static int dmatest_func(void *data) * free it this time?" dancing. For now, just * leave it dangling. */ + WARN(1, "dmatest: Kernel stack may be corrupted!!\n"); dmaengine_unmap_put(um); result("test timed out", total_tests, src_off, dst_off, len, 0); diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index f9028e9d0dfc..afd8f27bda96 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -123,7 +123,7 @@ struct pch_dma_chan { struct pch_dma { struct dma_device dma; void __iomem *membase; - struct pci_pool *pool; + struct dma_pool *pool; struct pch_dma_regs regs; struct pch_dma_desc_regs ch_regs[MAX_CHAN_NR]; struct pch_dma_chan channels[MAX_CHAN_NR]; @@ -437,7 +437,7 @@ static struct pch_dma_desc *pdc_alloc_desc(struct dma_chan *chan, gfp_t flags) struct pch_dma *pd = to_pd(chan->device); dma_addr_t addr; - desc = pci_pool_zalloc(pd->pool, flags, &addr); + desc = dma_pool_zalloc(pd->pool, flags, &addr); if (desc) { INIT_LIST_HEAD(&desc->tx_list); dma_async_tx_descriptor_init(&desc->txd, chan); @@ -549,7 +549,7 @@ static void pd_free_chan_resources(struct dma_chan *chan) spin_unlock_irq(&pd_chan->lock); list_for_each_entry_safe(desc, _d, &tmp_list, desc_node) - pci_pool_free(pd->pool, desc, desc->txd.phys); + dma_pool_free(pd->pool, desc, desc->txd.phys); pdc_enable_irq(chan, 0); } @@ -880,7 +880,7 @@ static int pch_dma_probe(struct pci_dev *pdev, goto err_iounmap; } - pd->pool = pci_pool_create("pch_dma_desc_pool", pdev, + pd->pool = dma_pool_create("pch_dma_desc_pool", &pdev->dev, sizeof(struct pch_dma_desc), 4, 0); if (!pd->pool) { dev_err(&pdev->dev, "Failed to alloc DMA descriptors\n"); @@ -931,7 +931,7 @@ static int pch_dma_probe(struct pci_dev *pdev, return 0; err_free_pool: - pci_pool_destroy(pd->pool); + dma_pool_destroy(pd->pool); err_free_irq: free_irq(pdev->irq, pd); err_iounmap: @@ -963,7 +963,7 @@ static void pch_dma_remove(struct pci_dev *pdev) tasklet_kill(&pd_chan->tasklet); } - pci_pool_destroy(pd->pool); + dma_pool_destroy(pd->pool); pci_iounmap(pdev, pd->membase); pci_release_regions(pdev); pci_disable_device(pdev); |