Commit c431b420 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dmaengine-fix-4.20-rc6' of git://git.infradead.org/users/vkoul/slave-dma

Pull dmaengine fixes from Vinod Koul:
 "Another pull request for dmaengine. We got bunch of fixes early this
  week and all are tagged to stable. Hope this is last fix for this
  cycle:

   - Fix imx-sdma handling of channel terminations, this involves
     reverting two commits and implement async termination

   - Fix cppi dma channel deletion from pending list on stop

   - Fix FIFO size for dw controller in Intel Merrifield"

* tag 'dmaengine-fix-4.20-rc6' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: dw: Fix FIFO size for Intel Merrifield
  dmaengine: cppi41: delete channel from pending list when stop channel
  dmaengine: imx-sdma: use GFP_NOWAIT for dma descriptor allocations
  dmaengine: imx-sdma: implement channel termination via worker
  Revert "dmaengine: imx-sdma: alloclate bd memory from dma pool"
  Revert "dmaengine: imx-sdma: Use GFP_NOWAIT for dma allocations"
parents d387ac13 ffe843b1
...@@ -1059,12 +1059,12 @@ static void dwc_issue_pending(struct dma_chan *chan) ...@@ -1059,12 +1059,12 @@ static void dwc_issue_pending(struct dma_chan *chan)
/* /*
* Program FIFO size of channels. * Program FIFO size of channels.
* *
* By default full FIFO (1024 bytes) is assigned to channel 0. Here we * By default full FIFO (512 bytes) is assigned to channel 0. Here we
* slice FIFO on equal parts between channels. * slice FIFO on equal parts between channels.
*/ */
static void idma32_fifo_partition(struct dw_dma *dw) static void idma32_fifo_partition(struct dw_dma *dw)
{ {
u64 value = IDMA32C_FP_PSIZE_CH0(128) | IDMA32C_FP_PSIZE_CH1(128) | u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) |
IDMA32C_FP_UPDATE; IDMA32C_FP_UPDATE;
u64 fifo_partition = 0; u64 fifo_partition = 0;
...@@ -1077,7 +1077,7 @@ static void idma32_fifo_partition(struct dw_dma *dw) ...@@ -1077,7 +1077,7 @@ static void idma32_fifo_partition(struct dw_dma *dw)
/* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */ /* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
fifo_partition |= value << 32; fifo_partition |= value << 32;
/* Program FIFO Partition registers - 128 bytes for each channel */ /* Program FIFO Partition registers - 64 bytes per channel */
idma32_writeq(dw, FIFO_PARTITION1, fifo_partition); idma32_writeq(dw, FIFO_PARTITION1, fifo_partition);
idma32_writeq(dw, FIFO_PARTITION0, fifo_partition); idma32_writeq(dw, FIFO_PARTITION0, fifo_partition);
} }
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -33,6 +32,7 @@ ...@@ -33,6 +32,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_dma.h> #include <linux/of_dma.h>
#include <linux/workqueue.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <linux/platform_data/dma-imx-sdma.h> #include <linux/platform_data/dma-imx-sdma.h>
...@@ -376,7 +376,7 @@ struct sdma_channel { ...@@ -376,7 +376,7 @@ struct sdma_channel {
u32 shp_addr, per_addr; u32 shp_addr, per_addr;
enum dma_status status; enum dma_status status;
struct imx_dma_data data; struct imx_dma_data data;
struct dma_pool *bd_pool; struct work_struct terminate_worker;
}; };
#define IMX_DMA_SG_LOOP BIT(0) #define IMX_DMA_SG_LOOP BIT(0)
...@@ -1027,31 +1027,49 @@ static int sdma_disable_channel(struct dma_chan *chan) ...@@ -1027,31 +1027,49 @@ static int sdma_disable_channel(struct dma_chan *chan)
return 0; return 0;
} }
static void sdma_channel_terminate_work(struct work_struct *work)
static int sdma_disable_channel_with_delay(struct dma_chan *chan)
{ {
struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_channel *sdmac = container_of(work, struct sdma_channel,
terminate_worker);
unsigned long flags; unsigned long flags;
LIST_HEAD(head); LIST_HEAD(head);
sdma_disable_channel(chan);
spin_lock_irqsave(&sdmac->vc.lock, flags);
vchan_get_all_descriptors(&sdmac->vc, &head);
sdmac->desc = NULL;
spin_unlock_irqrestore(&sdmac->vc.lock, flags);
vchan_dma_desc_free_list(&sdmac->vc, &head);
/* /*
* According to NXP R&D team a delay of one BD SDMA cost time * According to NXP R&D team a delay of one BD SDMA cost time
* (maximum is 1ms) should be added after disable of the channel * (maximum is 1ms) should be added after disable of the channel
* bit, to ensure SDMA core has really been stopped after SDMA * bit, to ensure SDMA core has really been stopped after SDMA
* clients call .device_terminate_all. * clients call .device_terminate_all.
*/ */
mdelay(1); usleep_range(1000, 2000);
spin_lock_irqsave(&sdmac->vc.lock, flags);
vchan_get_all_descriptors(&sdmac->vc, &head);
sdmac->desc = NULL;
spin_unlock_irqrestore(&sdmac->vc.lock, flags);
vchan_dma_desc_free_list(&sdmac->vc, &head);
}
static int sdma_disable_channel_async(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
sdma_disable_channel(chan);
if (sdmac->desc)
schedule_work(&sdmac->terminate_worker);
return 0; return 0;
} }
static void sdma_channel_synchronize(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
vchan_synchronize(&sdmac->vc);
flush_work(&sdmac->terminate_worker);
}
static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac) static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
{ {
struct sdma_engine *sdma = sdmac->sdma; struct sdma_engine *sdma = sdmac->sdma;
...@@ -1192,10 +1210,11 @@ static int sdma_request_channel0(struct sdma_engine *sdma) ...@@ -1192,10 +1210,11 @@ static int sdma_request_channel0(struct sdma_engine *sdma)
static int sdma_alloc_bd(struct sdma_desc *desc) static int sdma_alloc_bd(struct sdma_desc *desc)
{ {
u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
int ret = 0; int ret = 0;
desc->bd = dma_pool_alloc(desc->sdmac->bd_pool, GFP_NOWAIT, desc->bd = dma_zalloc_coherent(NULL, bd_size, &desc->bd_phys,
&desc->bd_phys); GFP_NOWAIT);
if (!desc->bd) { if (!desc->bd) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
...@@ -1206,7 +1225,9 @@ static int sdma_alloc_bd(struct sdma_desc *desc) ...@@ -1206,7 +1225,9 @@ static int sdma_alloc_bd(struct sdma_desc *desc)
static void sdma_free_bd(struct sdma_desc *desc) static void sdma_free_bd(struct sdma_desc *desc)
{ {
dma_pool_free(desc->sdmac->bd_pool, desc->bd, desc->bd_phys); u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
dma_free_coherent(NULL, bd_size, desc->bd, desc->bd_phys);
} }
static void sdma_desc_free(struct virt_dma_desc *vd) static void sdma_desc_free(struct virt_dma_desc *vd)
...@@ -1272,10 +1293,6 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan) ...@@ -1272,10 +1293,6 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
if (ret) if (ret)
goto disable_clk_ahb; goto disable_clk_ahb;
sdmac->bd_pool = dma_pool_create("bd_pool", chan->device->dev,
sizeof(struct sdma_buffer_descriptor),
32, 0);
return 0; return 0;
disable_clk_ahb: disable_clk_ahb:
...@@ -1290,7 +1307,9 @@ static void sdma_free_chan_resources(struct dma_chan *chan) ...@@ -1290,7 +1307,9 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma; struct sdma_engine *sdma = sdmac->sdma;
sdma_disable_channel_with_delay(chan); sdma_disable_channel_async(chan);
sdma_channel_synchronize(chan);
if (sdmac->event_id0) if (sdmac->event_id0)
sdma_event_disable(sdmac, sdmac->event_id0); sdma_event_disable(sdmac, sdmac->event_id0);
...@@ -1304,9 +1323,6 @@ static void sdma_free_chan_resources(struct dma_chan *chan) ...@@ -1304,9 +1323,6 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
clk_disable(sdma->clk_ipg); clk_disable(sdma->clk_ipg);
clk_disable(sdma->clk_ahb); clk_disable(sdma->clk_ahb);
dma_pool_destroy(sdmac->bd_pool);
sdmac->bd_pool = NULL;
} }
static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac, static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
...@@ -1999,6 +2015,8 @@ static int sdma_probe(struct platform_device *pdev) ...@@ -1999,6 +2015,8 @@ static int sdma_probe(struct platform_device *pdev)
sdmac->channel = i; sdmac->channel = i;
sdmac->vc.desc_free = sdma_desc_free; sdmac->vc.desc_free = sdma_desc_free;
INIT_WORK(&sdmac->terminate_worker,
sdma_channel_terminate_work);
/* /*
* Add the channel to the DMAC list. Do not add channel 0 though * Add the channel to the DMAC list. Do not add channel 0 though
* because we need it internally in the SDMA driver. This also means * because we need it internally in the SDMA driver. This also means
...@@ -2050,7 +2068,8 @@ static int sdma_probe(struct platform_device *pdev) ...@@ -2050,7 +2068,8 @@ static int sdma_probe(struct platform_device *pdev)
sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg; sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg;
sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic; sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
sdma->dma_device.device_config = sdma_config; sdma->dma_device.device_config = sdma_config;
sdma->dma_device.device_terminate_all = sdma_disable_channel_with_delay; sdma->dma_device.device_terminate_all = sdma_disable_channel_async;
sdma->dma_device.device_synchronize = sdma_channel_synchronize;
sdma->dma_device.src_addr_widths = SDMA_DMA_BUSWIDTHS; sdma->dma_device.src_addr_widths = SDMA_DMA_BUSWIDTHS;
sdma->dma_device.dst_addr_widths = SDMA_DMA_BUSWIDTHS; sdma->dma_device.dst_addr_widths = SDMA_DMA_BUSWIDTHS;
sdma->dma_device.directions = SDMA_DMA_DIRECTIONS; sdma->dma_device.directions = SDMA_DMA_DIRECTIONS;
......
...@@ -723,8 +723,22 @@ static int cppi41_stop_chan(struct dma_chan *chan) ...@@ -723,8 +723,22 @@ static int cppi41_stop_chan(struct dma_chan *chan)
desc_phys = lower_32_bits(c->desc_phys); desc_phys = lower_32_bits(c->desc_phys);
desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
if (!cdd->chan_busy[desc_num]) if (!cdd->chan_busy[desc_num]) {
struct cppi41_channel *cc, *_ct;
/*
* channels might still be in the pendling list if
* cppi41_dma_issue_pending() is called after
* cppi41_runtime_suspend() is called
*/
list_for_each_entry_safe(cc, _ct, &cdd->pending, node) {
if (cc != c)
continue;
list_del(&cc->node);
break;
}
return 0; return 0;
}
ret = cppi41_tear_down_chan(c); ret = cppi41_tear_down_chan(c);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment