diff options
author | Vinod Koul <vkoul@kernel.org> | 2020-08-05 19:02:07 +0530 |
---|---|---|
committer | Vinod Koul <vkoul@kernel.org> | 2020-08-05 19:02:07 +0530 |
commit | 0b5ad7b9522e6172342511fac6114fd8b7eb622a (patch) | |
tree | b6a29560e6364bd98634564181cab54a3b6164a4 /drivers/dma/dw | |
parent | 87730ccbddcb48478b1b88e88b14e73424130764 (diff) | |
parent | 6bd0dffa1a6e19e73964ae47c964f57c625cce05 (diff) | |
download | linux-0b5ad7b9522e6172342511fac6114fd8b7eb622a.tar.bz2 |
Merge branch 'for-linus' into fixes
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Conflicts:
drivers/dma/idxd/sysfs.c
Diffstat (limited to 'drivers/dma/dw')
-rw-r--r-- | drivers/dma/dw/Makefile | 6 | ||||
-rw-r--r-- | drivers/dma/dw/acpi.c | 2 | ||||
-rw-r--r-- | drivers/dma/dw/core.c | 48 | ||||
-rw-r--r-- | drivers/dma/dw/of.c | 5 | ||||
-rw-r--r-- | drivers/dma/dw/pci.c | 4 | ||||
-rw-r--r-- | drivers/dma/dw/regs.h | 3 |
6 files changed, 64 insertions, 4 deletions
diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile index b6f06699e91a..a6f358ad8591 100644 --- a/drivers/dma/dw/Makefile +++ b/drivers/dma/dw/Makefile @@ -1,11 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DW_DMAC_CORE) += dw_dmac_core.o -dw_dmac_core-objs := core.o dw.o idma32.o +dw_dmac_core-y := core.o dw.o idma32.o +dw_dmac_core-$(CONFIG_ACPI) += acpi.o obj-$(CONFIG_DW_DMAC) += dw_dmac.o dw_dmac-y := platform.o -dw_dmac-$(CONFIG_ACPI) += acpi.o dw_dmac-$(CONFIG_OF) += of.o obj-$(CONFIG_DW_DMAC_PCI) += dw_dmac_pci.o -dw_dmac_pci-objs := pci.o +dw_dmac_pci-y := pci.o diff --git a/drivers/dma/dw/acpi.c b/drivers/dma/dw/acpi.c index f6e8d55b4f6e..c510c109d2c3 100644 --- a/drivers/dma/dw/acpi.c +++ b/drivers/dma/dw/acpi.c @@ -41,6 +41,7 @@ void dw_dma_acpi_controller_register(struct dw_dma *dw) if (ret) dev_err(dev, "could not register acpi_dma_controller\n"); } +EXPORT_SYMBOL_GPL(dw_dma_acpi_controller_register); void dw_dma_acpi_controller_free(struct dw_dma *dw) { @@ -51,3 +52,4 @@ void dw_dma_acpi_controller_free(struct dw_dma *dw) acpi_dma_controller_free(dev); } +EXPORT_SYMBOL_GPL(dw_dma_acpi_controller_free); diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index a1b56f52db2f..4700f2e87a62 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -786,6 +786,11 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig) memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); + dwc->dma_sconfig.src_maxburst = + clamp(dwc->dma_sconfig.src_maxburst, 0U, dwc->max_burst); + dwc->dma_sconfig.dst_maxburst = + clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst); + dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst); dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst); @@ -1037,6 +1042,25 @@ static void dwc_free_chan_resources(struct dma_chan *chan) dev_vdbg(chan2dev(chan), "%s: done\n", __func__); } +static void dwc_caps(struct dma_chan *chan, struct dma_slave_caps *caps) +{ + struct dw_dma_chan *dwc = to_dw_dma_chan(chan); + + caps->max_burst = dwc->max_burst; + + /* + * It might be crucial for some devices to have the hardware + * accelerated multi-block transfers supported, aka LLPs in DW DMAC + * notation. So if LLPs are supported then max_sg_burst is set to + * zero which means unlimited number of SG entries can be handled in a + * single DMA transaction, otherwise it's just one SG entry. + */ + if (dwc->nollp) + caps->max_sg_burst = 1; + else + caps->max_sg_burst = 0; +} + int do_dma_probe(struct dw_dma_chip *chip) { struct dw_dma *dw = chip->dw; @@ -1166,11 +1190,23 @@ int do_dma_probe(struct dw_dma_chip *chip) */ dwc->block_size = (4 << ((pdata->block_size >> 4 * i) & 0xf)) - 1; + + /* + * According to the DW DMA databook the true scatter- + * gether LLPs aren't available if either multi-block + * config is disabled (CHx_MULTI_BLK_EN == 0) or the + * LLP register is hard-coded to zeros + * (CHx_HC_LLP == 1). + */ dwc->nollp = - (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0; + (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0 || + (dwc_params >> DWC_PARAMS_HC_LLP & 0x1) == 1; + dwc->max_burst = + (0x4 << (dwc_params >> DWC_PARAMS_MSIZE & 0x7)); } else { dwc->block_size = pdata->block_size; dwc->nollp = !pdata->multi_block[i]; + dwc->max_burst = pdata->max_burst[i] ?: DW_DMA_MAX_BURST; } } @@ -1193,6 +1229,7 @@ int do_dma_probe(struct dw_dma_chip *chip) dw->dma.device_prep_dma_memcpy = dwc_prep_dma_memcpy; dw->dma.device_prep_slave_sg = dwc_prep_slave_sg; + dw->dma.device_caps = dwc_caps; dw->dma.device_config = dwc_config; dw->dma.device_pause = dwc_pause; dw->dma.device_resume = dwc_resume; @@ -1202,12 +1239,21 @@ int do_dma_probe(struct dw_dma_chip *chip) dw->dma.device_issue_pending = dwc_issue_pending; /* DMA capabilities */ + dw->dma.min_burst = DW_DMA_MIN_BURST; + dw->dma.max_burst = DW_DMA_MAX_BURST; dw->dma.src_addr_widths = DW_DMA_BUSWIDTHS; dw->dma.dst_addr_widths = DW_DMA_BUSWIDTHS; dw->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | BIT(DMA_MEM_TO_MEM); dw->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + /* + * For now there is no hardware with non uniform maximum block size + * across all of the device channels, so we set the maximum segment + * size as the block size found for the very first channel. + */ + dma_set_max_seg_size(dw->dma.dev, dw->chan[0].block_size); + err = dma_async_device_register(&dw->dma); if (err) goto err_dma_register; diff --git a/drivers/dma/dw/of.c b/drivers/dma/dw/of.c index 9e27831dee32..1474b3817ef4 100644 --- a/drivers/dma/dw/of.c +++ b/drivers/dma/dw/of.c @@ -98,6 +98,11 @@ struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) pdata->multi_block[tmp] = 1; } + if (of_property_read_u32_array(np, "snps,max-burst-len", pdata->max_burst, + nr_channels)) { + memset32(pdata->max_burst, DW_DMA_MAX_BURST, nr_channels); + } + if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { if (tmp > CHAN_PROTCTL_MASK) return NULL; diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index cf6e8ec4c0ff..1142aa6f8c4a 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -60,6 +60,8 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) if (ret) return ret; + dw_dma_acpi_controller_register(chip->dw); + pci_set_drvdata(pdev, data); return 0; @@ -71,6 +73,8 @@ static void dw_pci_remove(struct pci_dev *pdev) struct dw_dma_chip *chip = data->chip; int ret; + dw_dma_acpi_controller_free(chip->dw); + ret = data->remove(chip); if (ret) dev_warn(&pdev->dev, "can't remove device properly: %d\n", ret); diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 3fce66ecee7a..76654bd13c1a 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -125,6 +125,8 @@ struct dw_dma_regs { /* Bitfields in DWC_PARAMS */ #define DWC_PARAMS_MBLK_EN 11 /* multi block transfer */ +#define DWC_PARAMS_HC_LLP 13 /* set LLP register to zero */ +#define DWC_PARAMS_MSIZE 16 /* max group transaction size */ /* bursts size */ enum dw_dma_msize { @@ -283,6 +285,7 @@ struct dw_dma_chan { /* hardware configuration */ unsigned int block_size; bool nollp; + u32 max_burst; /* custom slave configuration */ struct dw_dma_slave dws; |