diff options
47 files changed, 772 insertions, 246 deletions
diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd index 1af9c4175213..b44183880935 100644 --- a/Documentation/ABI/stable/sysfs-driver-dma-idxd +++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd @@ -116,6 +116,12 @@ Description: The maximum number of bandwidth tokens that may be in use at one time by operations that access low bandwidth memory in the device. +What: /sys/bus/dsa/devices/dsa<m>/cmd_status +Date: Aug 28, 2020 +KernelVersion: 5.10.0 +Contact: [email protected] +Description: The last executed device administrative command's status/error. + What: /sys/bus/dsa/devices/wq<m>.<n>/group_id Date: Oct 25, 2019 KernelVersion: 5.6.0 @@ -170,6 +176,20 @@ Contact: [email protected] Description: The number of entries in this work queue that may be filled via a limited portal. +What: /sys/bus/dsa/devices/wq<m>.<n>/max_transfer_size +Date: Aug 28, 2020 +KernelVersion: 5.10.0 +Contact: [email protected] +Description: The max transfer sized for this workqueue. Cannot exceed device + max transfer size. Configurable parameter. + +What: /sys/bus/dsa/devices/wq<m>.<n>/max_batch_size +Date: Aug 28, 2020 +KernelVersion: 5.10.0 +Contact: [email protected] +Description: The max batch size for this workqueue. Cannot exceed device + max batch size. Configurable parameter. + What: /sys/bus/dsa/devices/engine<m>.<n>/group_id Date: Oct 25, 2019 KernelVersion: 5.6.0 diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.yaml b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.yaml index 13f1a46be40d..b548e4723936 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.yaml @@ -16,6 +16,7 @@ properties: compatible: items: - enum: + - renesas,dmac-r8a7742 # RZ/G1H - renesas,dmac-r8a7743 # RZ/G1M - renesas,dmac-r8a7744 # RZ/G1N - renesas,dmac-r8a7745 # RZ/G1E diff --git a/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml b/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml index 20870f5c14dd..ef1d6879c158 100644 --- a/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml +++ b/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml @@ -18,12 +18,15 @@ properties: const: snps,dma-spear1340 "#dma-cells": - const: 3 + minimum: 3 + maximum: 4 description: | First cell is a phandle pointing to the DMA controller. Second one is the DMA request line number. Third cell is the memory master identifier for transfers on dynamically allocated channel. Fourth cell is the - peripheral master identifier for transfers on an allocated channel. + peripheral master identifier for transfers on an allocated channel. Fifth + cell is an optional mask of the DMA channels permitted to be allocated + for the corresponding client device. reg: maxItems: 1 diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 4768ef26013b..630dfbb01a40 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -41,14 +41,12 @@ * struct bcm2835_dmadev - BCM2835 DMA controller * @ddev: DMA device * @base: base address of register map - * @dma_parms: DMA parameters (to convey 1 GByte max segment size to clients) * @zero_page: bus address of zero page (to detect transactions copying from * zero page and avoid accessing memory if so) */ struct bcm2835_dmadev { struct dma_device ddev; void __iomem *base; - struct device_dma_parameters dma_parms; dma_addr_t zero_page; }; @@ -902,7 +900,6 @@ static int bcm2835_dma_probe(struct platform_device *pdev) if (!od) return -ENOMEM; - pdev->dev.dma_parms = &od->dma_parms; dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index f1d149e32839..5161b73c30c4 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -6,6 +6,7 @@ * Author: Lars-Peter Clausen <[email protected]> */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/dma-mapping.h> @@ -45,6 +46,16 @@ * there is no address than can or needs to be configured for the device side. */ +#define AXI_DMAC_REG_INTERFACE_DESC 0x10 +#define AXI_DMAC_DMA_SRC_TYPE_MSK GENMASK(13, 12) +#define AXI_DMAC_DMA_SRC_TYPE_GET(x) FIELD_GET(AXI_DMAC_DMA_SRC_TYPE_MSK, x) +#define AXI_DMAC_DMA_SRC_WIDTH_MSK GENMASK(11, 8) +#define AXI_DMAC_DMA_SRC_WIDTH_GET(x) FIELD_GET(AXI_DMAC_DMA_SRC_WIDTH_MSK, x) +#define AXI_DMAC_DMA_DST_TYPE_MSK GENMASK(5, 4) +#define AXI_DMAC_DMA_DST_TYPE_GET(x) FIELD_GET(AXI_DMAC_DMA_DST_TYPE_MSK, x) +#define AXI_DMAC_DMA_DST_WIDTH_MSK GENMASK(3, 0) +#define AXI_DMAC_DMA_DST_WIDTH_GET(x) FIELD_GET(AXI_DMAC_DMA_DST_WIDTH_MSK, x) + #define AXI_DMAC_REG_IRQ_MASK 0x80 #define AXI_DMAC_REG_IRQ_PENDING 0x84 #define AXI_DMAC_REG_IRQ_SOURCE 0x88 @@ -134,8 +145,6 @@ struct axi_dmac { struct dma_device dma_dev; struct axi_dmac_chan chan; - - struct device_dma_parameters dma_parms; }; static struct axi_dmac *chan_to_axi_dmac(struct axi_dmac_chan *chan) @@ -717,6 +726,20 @@ static const struct regmap_config axi_dmac_regmap_config = { .writeable_reg = axi_dmac_regmap_rdwr, }; +static void axi_dmac_adjust_chan_params(struct axi_dmac_chan *chan) +{ + chan->address_align_mask = max(chan->dest_width, chan->src_width) - 1; + + if (axi_dmac_dest_is_mem(chan) && axi_dmac_src_is_mem(chan)) + chan->direction = DMA_MEM_TO_MEM; + else if (!axi_dmac_dest_is_mem(chan) && axi_dmac_src_is_mem(chan)) + chan->direction = DMA_MEM_TO_DEV; + else if (axi_dmac_dest_is_mem(chan) && !axi_dmac_src_is_mem(chan)) + chan->direction = DMA_DEV_TO_MEM; + else + chan->direction = DMA_DEV_TO_DEV; +} + /* * The configuration stored in the devicetree matches the configuration * parameters of the peripheral instance and allows the driver to know which @@ -760,26 +783,81 @@ static int axi_dmac_parse_chan_dt(struct device_node *of_chan, return ret; chan->dest_width = val / 8; - chan->address_align_mask = max(chan->dest_width, chan->src_width) - 1; + axi_dmac_adjust_chan_params(chan); - if (axi_dmac_dest_is_mem(chan) && axi_dmac_src_is_mem(chan)) - chan->direction = DMA_MEM_TO_MEM; - else if (!axi_dmac_dest_is_mem(chan) && axi_dmac_src_is_mem(chan)) - chan->direction = DMA_MEM_TO_DEV; - else if (axi_dmac_dest_is_mem(chan) && !axi_dmac_src_is_mem(chan)) - chan->direction = DMA_DEV_TO_MEM; - else - chan->direction = DMA_DEV_TO_DEV; + return 0; +} + +static int axi_dmac_parse_dt(struct device *dev, struct axi_dmac *dmac) +{ + struct device_node *of_channels, *of_chan; + int ret; + + of_channels = of_get_child_by_name(dev->of_node, "adi,channels"); + if (of_channels == NULL) + return -ENODEV; + + for_each_child_of_node(of_channels, of_chan) { + ret = axi_dmac_parse_chan_dt(of_chan, &dmac->chan); + if (ret) { + of_node_put(of_chan); + of_node_put(of_channels); + return -EINVAL; + } + } + of_node_put(of_channels); return 0; } -static int axi_dmac_detect_caps(struct axi_dmac *dmac) +static int axi_dmac_read_chan_config(struct device *dev, struct axi_dmac *dmac) { struct axi_dmac_chan *chan = &dmac->chan; - unsigned int version; + unsigned int val, desc; - version = axi_dmac_read(dmac, ADI_AXI_REG_VERSION); + desc = axi_dmac_read(dmac, AXI_DMAC_REG_INTERFACE_DESC); + if (desc == 0) { + dev_err(dev, "DMA interface register reads zero\n"); + return -EFAULT; + } + + val = AXI_DMAC_DMA_SRC_TYPE_GET(desc); + if (val > AXI_DMAC_BUS_TYPE_FIFO) { + dev_err(dev, "Invalid source bus type read: %d\n", val); + return -EINVAL; + } + chan->src_type = val; + + val = AXI_DMAC_DMA_DST_TYPE_GET(desc); + if (val > AXI_DMAC_BUS_TYPE_FIFO) { + dev_err(dev, "Invalid destination bus type read: %d\n", val); + return -EINVAL; + } + chan->dest_type = val; + + val = AXI_DMAC_DMA_SRC_WIDTH_GET(desc); + if (val == 0) { + dev_err(dev, "Source bus width is zero\n"); + return -EINVAL; + } + /* widths are stored in log2 */ + chan->src_width = 1 << val; + + val = AXI_DMAC_DMA_DST_WIDTH_GET(desc); + if (val == 0) { + dev_err(dev, "Destination bus width is zero\n"); + return -EINVAL; + } + chan->dest_width = 1 << val; + + axi_dmac_adjust_chan_params(chan); + + return 0; +} + +static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version) +{ + struct axi_dmac_chan *chan = &dmac->chan; axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, AXI_DMAC_FLAG_CYCLIC); if (axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS) == AXI_DMAC_FLAG_CYCLIC) @@ -826,11 +904,11 @@ static int axi_dmac_detect_caps(struct axi_dmac *dmac) static int axi_dmac_probe(struct platform_device *pdev) { - struct device_node *of_channels, *of_chan; struct dma_device *dma_dev; struct axi_dmac *dmac; struct resource *res; struct regmap *regmap; + unsigned int version; int ret; dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL); @@ -852,23 +930,22 @@ static int axi_dmac_probe(struct platform_device *pdev) if (IS_ERR(dmac->clk)) return PTR_ERR(dmac->clk); - INIT_LIST_HEAD(&dmac->chan.active_descs); + ret = clk_prepare_enable(dmac->clk); + if (ret < 0) + return ret; - of_channels = of_get_child_by_name(pdev->dev.of_node, "adi,channels"); - if (of_channels == NULL) - return -ENODEV; + version = axi_dmac_read(dmac, ADI_AXI_REG_VERSION); - for_each_child_of_node(of_channels, of_chan) { - ret = axi_dmac_parse_chan_dt(of_chan, &dmac->chan); - if (ret) { - of_node_put(of_chan); - of_node_put(of_channels); - return -EINVAL; - } - } - of_node_put(of_channels); + if (version >= ADI_AXI_PCORE_VER(4, 3, 'a')) + ret = axi_dmac_read_chan_config(&pdev->dev, dmac); + else + ret = axi_dmac_parse_dt(&pdev->dev, dmac); + + if (ret < 0) + goto err_clk_disable; + + INIT_LIST_HEAD(&dmac->chan.active_descs); - pdev->dev.dma_parms = &dmac->dma_parms; dma_set_max_seg_size(&pdev->dev, UINT_MAX); dma_dev = &dmac->dma_dev; @@ -894,11 +971,7 @@ static int axi_dmac_probe(struct platform_device *pdev) dmac->chan.vchan.desc_free = axi_dmac_desc_free; vchan_init(&dmac->chan.vchan, dma_dev); - ret = clk_prepare_enable(dmac->clk); - if (ret < 0) - return ret; - - ret = axi_dmac_detect_caps(dmac); + ret = axi_dmac_detect_caps(dmac, version); if (ret) goto err_clk_disable; diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index a53e71d2bbd4..7974fa0400d8 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -847,8 +847,10 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name) } mutex_unlock(&dma_list_mutex); - if (IS_ERR_OR_NULL(chan)) - return chan ? chan : ERR_PTR(-EPROBE_DEFER); + if (IS_ERR(chan)) + return chan; + if (!chan) + return ERR_PTR(-EPROBE_DEFER); found: #ifdef CONFIG_DEBUG_FS @@ -872,24 +874,6 @@ found: EXPORT_SYMBOL_GPL(dma_request_chan); /** - * dma_request_slave_channel - try to allocate an exclusive slave channel - * @dev: pointer to client device structure - * @name: slave channel name - * - * Returns pointer to appropriate DMA channel on success or NULL. - */ -struct dma_chan *dma_request_slave_channel(struct device *dev, - const char *name) -{ - struct dma_chan *ch = dma_request_chan(dev, name); - if (IS_ERR(ch)) - return NULL; - - return ch; -} -EXPORT_SYMBOL_GPL(dma_request_slave_channel); - -/** * dma_request_chan_by_mask - allocate a channel satisfying certain capabilities * @mask: capabilities that the channel must satisfy * diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index a819611b8892..5dc3db216602 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -7,6 +7,7 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/err.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> @@ -454,8 +455,13 @@ static unsigned int min_odd(unsigned int x, unsigned int y) static void result(const char *err, unsigned int n, unsigned int src_off, unsigned int dst_off, unsigned int len, unsigned long data) { - pr_info("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)\n", - current->comm, n, err, src_off, dst_off, len, data); + if (IS_ERR_VALUE(data)) { + pr_info("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%ld)\n", + current->comm, n, err, src_off, dst_off, len, data); + } else { + pr_info("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)\n", + current->comm, n, err, src_off, dst_off, len, data); + } } static void dbg_result(const char *err, unsigned int n, unsigned int src_off, diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c index 42739508c0d8..6f62711a4c94 100644 --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c @@ -293,7 +293,7 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip) if (!regs) return; - base_dir = debugfs_create_dir(dw->name, 0); + base_dir = debugfs_create_dir(dw->name, NULL); if (!base_dir) return; diff --git a/drivers/dma/dw-edma/dw-edma-v0-regs.h b/drivers/dma/dw-edma/dw-edma-v0-regs.h index cd6476884507..dfd70e223c2f 100644 --- a/drivers/dma/dw-edma/dw-edma-v0-regs.h +++ b/drivers/dma/dw-edma/dw-edma-v0-regs.h @@ -40,7 +40,7 @@ struct dw_edma_v0_ch { struct dw_edma_v0_ch_regs wr; /* 0x200 */ u32 padding_1[55]; /* [0x224..0x2fc] */ struct dw_edma_v0_ch_regs rd; /* 0x300 */ - u32 padding_2[55]; /* [0x224..0x2fc] */ + u32 padding_2[55]; /* [0x324..0x3fc] */ }; struct dw_edma_v0_unroll { diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 4700f2e87a62..5f7b9badb965 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -723,7 +723,7 @@ slave_sg_fromdev_fill_desc: lli_write(desc, sar, reg); lli_write(desc, dar, mem); lli_write(desc, ctlhi, ctlhi); - mem_width = __ffs(data_width | mem | dlen); + mem_width = __ffs(data_width | mem); lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width)); desc->len = dlen; @@ -772,6 +772,10 @@ bool dw_dma_filter(struct dma_chan *chan, void *param) if (dws->dma_dev != chan->device->dev) return false; + /* permit channels in accordance with the channels mask */ + if (dws->channels && !(dws->channels & dwc->mask)) + return false; + /* We have to copy data since dws can be temporary storage */ memcpy(&dwc->dws, dws, sizeof(struct dw_dma_slave)); diff --git a/drivers/dma/dw/dw.c b/drivers/dma/dw/dw.c index 7a085b3c1854..a4862263ff14 100644 --- a/drivers/dma/dw/dw.c +++ b/drivers/dma/dw/dw.c @@ -14,7 +14,7 @@ static void dw_dma_initialize_chan(struct dw_dma_chan *dwc) { struct dw_dma *dw = to_dw_dma(dwc->chan.device); - u32 cfghi = DWC_CFGH_FIFO_MODE; + u32 cfghi = is_slave_direction(dwc->direction) ? 0 : DWC_CFGH_FIFO_MODE; u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); bool hs_polarity = dwc->dws.hs_polarity; @@ -67,9 +67,8 @@ static size_t dw_dma_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width) static u32 dw_dma_prepare_ctllo(struct dw_dma_chan *dwc) { struct dma_slave_config *sconfig = &dwc->dma_sconfig; - bool is_slave = is_slave_direction(dwc->direction); - u8 smsize = is_slave ? sconfig->src_maxburst : DW_DMA_MSIZE_16; - u8 dmsize = is_slave ? sconfig->dst_maxburst : DW_DMA_MSIZE_16; + u8 smsize = (dwc->direction == DMA_DEV_TO_MEM) ? sconfig->src_maxburst : 0; + u8 dmsize = (dwc->direction == DMA_MEM_TO_DEV) ? sconfig->dst_maxburst : 0; u8 p_master = dwc->dws.p_master; u8 m_master = dwc->dws.m_master; u8 dms = (dwc->direction == DMA_MEM_TO_DEV) ? p_master : m_master; diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c index f00657308811..3ce44de25d33 100644 --- a/drivers/dma/dw/idma32.c +++ b/drivers/dma/dw/idma32.c @@ -73,9 +73,8 @@ static size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width) static u32 idma32_prepare_ctllo(struct dw_dma_chan *dwc) { struct dma_slave_config *sconfig = &dwc->dma_sconfig; - bool is_slave = is_slave_direction(dwc->direction); - u8 smsize = is_slave ? sconfig->src_maxburst : IDMA32_MSIZE_8; - u8 dmsize = is_slave ? sconfig->dst_maxburst : IDMA32_MSIZE_8; + u8 smsize = (dwc->direction == DMA_DEV_TO_MEM) ? sconfig->src_maxburst : 0; + u8 dmsize = (dwc->direction == DMA_MEM_TO_DEV) ? sconfig->dst_maxburst : 0; return DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN | DWC_CTLL_DST_MSIZE(dmsize) | DWC_CTLL_SRC_MSIZE(smsize); diff --git a/drivers/dma/dw/of.c b/drivers/dma/dw/of.c index 1474b3817ef4..c1cf7675b9d1 100644 --- a/drivers/dma/dw/of.c +++ b/drivers/dma/dw/of.c @@ -22,18 +22,21 @@ static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, }; dma_cap_mask_t cap; - if (dma_spec->args_count != 3) + if (dma_spec->args_count < 3 || dma_spec->args_count > 4) return NULL; slave.src_id = dma_spec->args[0]; slave.dst_id = dma_spec->args[0]; slave.m_master = dma_spec->args[1]; slave.p_master = dma_spec->args[2]; + if (dma_spec->args_count >= 4) + slave.channels = dma_spec->args[3]; if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS || slave.dst_id >= DW_DMA_MAX_NR_REQUESTS || slave.m_master >= dw->pdata->nr_masters || - slave.p_master >= dw->pdata->nr_masters)) + slave.p_master >= dw->pdata->nr_masters || + slave.channels >= BIT(dw->pdata->nr_channels))) return NULL; dma_cap_zero(cap); diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index b75d699160bf..200b9109cacf 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -368,6 +368,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand, dev_dbg(&idxd->pdev->dev, "%s: sending cmd: %#x op: %#x\n", __func__, cmd_code, operand); + idxd->cmd_status = 0; __set_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags); idxd->cmd_done = &done; iowrite32(cmd.bits, idxd->reg_base + IDXD_CMD_OFFSET); @@ -379,8 +380,11 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand, spin_unlock_irqrestore(&idxd->dev_lock, flags); wait_for_completion(&done); spin_lock_irqsave(&idxd->dev_lock, flags); - if (status) + if (status) { *status = ioread32(idxd->reg_base + IDXD_CMDSTS_OFFSET); + idxd->cmd_status = *status & GENMASK(7, 0); + } + __clear_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags); /* Wake up other pending commands */ wake_up(&idxd->cmd_waitq); @@ -555,8 +559,8 @@ static int idxd_wq_config_write(struct idxd_wq *wq) wq->wqcfg.priority = wq->priority; /* bytes 12-15 */ - wq->wqcfg.max_xfer_shift = idxd->hw.gen_cap.max_xfer_shift; - wq->wqcfg.max_batch_shift = idxd->hw.gen_cap.max_batch_shift; + wq->wqcfg.max_xfer_shift = ilog2(wq->max_xfer_bytes); + wq->wqcfg.max_batch_shift = ilog2(wq->max_batch_size); dev_dbg(dev, "WQ %d CFGs\n", wq->id); for (i = 0; i < 8; i++) { diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index e62b4799d189..c64df197e724 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -114,6 +114,8 @@ struct idxd_wq { struct sbitmap_queue sbq; struct dma_chan dma_chan; char name[WQ_NAME_SIZE + 1]; + u64 max_xfer_bytes; + u32 max_batch_size; }; struct idxd_engine { @@ -154,6 +156,7 @@ struct idxd_device { unsigned long flags; int id; int major; + u8 cmd_status; struct pci_dev *pdev; void __iomem *reg_base; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index c7c61974f20f..11e5ce168177 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -176,6 +176,8 @@ static int idxd_setup_internals(struct idxd_device *idxd) wq->idxd = idxd; mutex_init(&wq->wq_lock); wq->idxd_cdev.minor = -1; + wq->max_xfer_bytes = idxd->max_xfer_bytes; + wq->max_batch_size = idxd->max_batch_size; } for (i = 0; i < idxd->max_engines; i++) { diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index 1e9e6991f543..17a65a13fb64 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -64,6 +64,7 @@ irqreturn_t idxd_misc_thread(int vec, void *data) bool err = false; cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET); + iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET); if (cause & IDXD_INTC_ERR) { spin_lock_bh(&idxd->dev_lock); @@ -121,7 +122,6 @@ irqreturn_t idxd_misc_thread(int vec, void *data) dev_warn_once(dev, "Unexpected interrupt cause bits set: %#x\n", val); - iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET); if (!err) goto out; diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index dcba60953217..07a5db06a29a 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -1064,6 +1064,89 @@ static ssize_t wq_cdev_minor_show(struct device *dev, static struct device_attribute dev_attr_wq_cdev_minor = __ATTR(cdev_minor, 0444, wq_cdev_minor_show, NULL); +static int __get_sysfs_u64(const char *buf, u64 *val) +{ + int rc; + + rc = kstrtou64(buf, 0, val); + if (rc < 0) + return -EINVAL; + + if (*val == 0) + return -EINVAL; + + *val = roundup_pow_of_two(*val); + return 0; +} + +static ssize_t wq_max_transfer_size_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + + return sprintf(buf, "%llu\n", wq->max_xfer_bytes); +} + +static ssize_t wq_max_transfer_size_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_device *idxd = wq->idxd; + u64 xfer_size; + int rc; + + if (wq->state != IDXD_WQ_DISABLED) + return -EPERM; + + rc = __get_sysfs_u64(buf, &xfer_size); + if (rc < 0) + return rc; + + if (xfer_size > idxd->max_xfer_bytes) + return -EINVAL; + + wq->max_xfer_bytes = xfer_size; + + return count; +} + +static struct device_attribute dev_attr_wq_max_transfer_size = + __ATTR(max_transfer_size, 0644, + wq_max_transfer_size_show, wq_max_transfer_size_store); + +static ssize_t wq_max_batch_size_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + + return sprintf(buf, "%u\n", wq->max_batch_size); +} + +static ssize_t wq_max_batch_size_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_device *idxd = wq->idxd; + u64 batch_size; + int rc; + + if (wq->state != IDXD_WQ_DISABLED) + return -EPERM; + + rc = __get_sysfs_u64(buf, &batch_size); + if (rc < 0) + return rc; + + if (batch_size > idxd->max_batch_size) + return -EINVAL; + + wq->max_batch_size = (u32)batch_size; + + return count; +} + +static struct device_attribute dev_attr_wq_max_batch_size = + __ATTR(max_batch_size, 0644, wq_max_batch_size_show, wq_max_batch_size_store); + static struct attribute *idxd_wq_attributes[] = { &dev_attr_wq_clients.attr, &dev_attr_wq_state.attr, @@ -1074,6 +1157,8 @@ static struct attribute *idxd_wq_attributes[] = { &dev_attr_wq_type.attr, &dev_attr_wq_name.attr, &dev_attr_wq_cdev_minor.attr, + &dev_attr_wq_max_transfer_size.attr, + &dev_attr_wq_max_batch_size.attr, NULL, }; @@ -1317,6 +1402,15 @@ static ssize_t cdev_major_show(struct device *dev, } static DEVICE_ATTR_RO(cdev_major); +static ssize_t cmd_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct idxd_device *idxd = container_of(dev, struct idxd_device, conf_dev); + + return sprintf(buf, "%#x\n", idxd->cmd_status); +} +static DEVICE_ATTR_RO(cmd_status); + static struct attribute *idxd_device_attributes[] = { &dev_attr_version.attr, &dev_attr_max_groups.attr, @@ -1335,6 +1429,7 @@ static struct attribute *idxd_device_attributes[] = { &dev_attr_max_tokens.attr, &dev_attr_token_limit.attr, &dev_attr_cdev_major.attr, + &dev_attr_cmd_status.attr, NULL, }; diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 88717506c1f6..67ac2e68707e 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -173,7 +173,6 @@ enum imx_dma_type { struct imxdma_engine { struct device *dev; - struct device_dma_parameters dma_parms; struct dma_device dma_device; void __iomem *base; struct clk *dma_ahb; @@ -1196,7 +1195,6 @@ static int __init imxdma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, imxdma); imxdma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES; - imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms; dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff); ret = dma_async_device_register(&imxdma->dma_device); diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 4f8d8f5e1132..16b908c77db3 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -426,7 +426,6 @@ struct sdma_driver_data { struct sdma_engine { struct device *dev; - struct device_dma_parameters dma_parms; struct sdma_channel channel[MAX_DMA_CHANNELS]; struct sdma_channel_control *channel_control; void __iomem *regs; @@ -2118,7 +2117,6 @@ static int sdma_probe(struct platform_device *pdev) sdma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; sdma->dma_device.device_prep_dma_memcpy = sdma_prep_memcpy; sdma->dma_device.device_issue_pending = sdma_issue_pending; - sdma->dma_device.dev->dma_parms = &sdma->dma_parms; sdma->dma_device.copy_align = 2; dma_set_max_seg_size(sdma->dma_device.dev, SDMA_BD_MAX_CNT); diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index a814b200299b..8cce4e059b7a 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -26,11 +26,11 @@ #include "../dmaengine.h" -int completion_timeout = 200; +static int completion_timeout = 200; module_param(completion_timeout, int, 0644); MODULE_PARM_DESC(completion_timeout, "set ioat completion timeout [msec] (default 200 [msec])"); -int idle_timeout = 2000; +static int idle_timeout = 2000; module_param(idle_timeout, int, 0644); MODULE_PARM_DESC(idle_timeout, "set ioat idel timeout [msec] (default 2000 [msec])"); diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 3350bffb2e93..48d56c9f3619 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -416,6 +416,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan); static int iop_adma_alloc_chan_resources(struct dma_chan *chan) { char *hw_desc; + dma_addr_t dma_desc; int idx; struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); struct iop_adma_desc_slot *slot = NULL; @@ -444,9 +445,8 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan) INIT_LIST_HEAD(&slot->tx_list); INIT_LIST_HEAD(&slot->chain_node); INIT_LIST_HEAD(&slot->slot_node); - hw_desc = (char *) iop_chan->device->dma_desc_pool; - slot->async_tx.phys = - (dma_addr_t) &hw_desc[idx * IOP_ADMA_SLOT_SIZE]; + dma_desc = iop_chan->device->dma_desc_pool; + slot->async_tx.phys = dma_desc + idx * IOP_ADMA_SLOT_SIZE; slot->idx = idx; spin_lock_bh(&iop_chan->lock); @@ -1296,9 +1296,8 @@ static int iop_adma_probe(struct platform_device *pdev) goto err_free_adev; } - dev_dbg(&pdev->dev, "%s: allocated descriptor pool virt %p phys %p\n", - __func__, adev->dma_desc_pool_virt, - (void *) adev->dma_desc_pool); + dev_dbg(&pdev->dev, "%s: allocated descriptor pool virt %p phys %pad\n", + __func__, adev->dma_desc_pool_virt, &adev->dma_desc_pool); adev->id = plat_data->hw_id; diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c index 29f1223b285a..27c07350971d 100644 --- a/drivers/dma/mediatek/mtk-uart-apdma.c +++ b/drivers/dma/mediatek/mtk-uart-apdma.c @@ -624,14 +624,9 @@ static int mtk_uart_apdma_runtime_suspend(struct device *dev) static int mtk_uart_apdma_runtime_resume(struct device *dev) { - int ret; struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev); - ret = clk_prepare_enable(mtkd->clk); - if (ret) - return ret; - - return 0; + return clk_prepare_enable(mtkd->clk); } #endif /* CONFIG_PM */ diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index 3039bba0e4d5..eb60eb72632e 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -141,7 +141,6 @@ struct mxs_dma_engine { void __iomem *base; struct clk *clk; struct dma_device dma_device; - struct device_dma_parameters dma_parms; struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS]; struct platform_device *pdev; unsigned int nr_channels; @@ -829,7 +828,6 @@ static int __init mxs_dma_probe(struct platform_device *pdev) mxs_dma->dma_device.dev = &pdev->dev; /* mxs_dma gets 65535 bytes maximum sg size */ - mxs_dma->dma_device.dev->dma_parms = &mxs_dma->dma_parms; dma_set_max_seg_size(mxs_dma->dma_device.dev, MAX_XFER_BYTES); mxs_dma->dma_device.device_alloc_chan_resources = mxs_dma_alloc_chan_resources; diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index a3b0b4c56a19..e93005837e3f 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -735,8 +735,7 @@ static irqreturn_t pd_irq(int irq, void *devid) return ret0 | ret2; } -#ifdef CONFIG_PM -static void pch_dma_save_regs(struct pch_dma *pd) +static void __maybe_unused pch_dma_save_regs(struct pch_dma *pd) { struct pch_dma_chan *pd_chan; struct dma_chan *chan, *_c; @@ -759,7 +758,7 @@ static void pch_dma_save_regs(struct pch_dma *pd) } } -static void pch_dma_restore_regs(struct pch_dma *pd) +static void __maybe_unused pch_dma_restore_regs(struct pch_dma *pd) { struct pch_dma_chan *pd_chan; struct dma_chan *chan, *_c; @@ -782,40 +781,25 @@ static void pch_dma_restore_regs(struct pch_dma *pd) } } -static int pch_dma_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused pch_dma_suspend(struct device *dev) { - struct pch_dma *pd = pci_get_drvdata(pdev); + struct pch_dma *pd = dev_get_drvdata(dev); if (pd) pch_dma_save_regs(pd); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } -static int pch_dma_resume(struct pci_dev *pdev) +static int __maybe_unused pch_dma_resume(struct device *dev) { - struct pch_dma *pd = pci_get_drvdata(pdev); - int err; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - err = pci_enable_device(pdev); - if (err) { - dev_dbg(&pdev->dev, "failed to enable device\n"); - return err; - } + struct pch_dma *pd = dev_get_drvdata(dev); if (pd) pch_dma_restore_regs(pd); return 0; } -#endif static int pch_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -993,15 +977,14 @@ static const struct pci_device_id pch_dma_id_table[] = { { 0, }, }; +static SIMPLE_DEV_PM_OPS(pch_dma_pm_ops, pch_dma_suspend, pch_dma_resume); + static struct pci_driver pch_dma_driver = { .name = DRV_NAME, .id_table = pch_dma_id_table, .probe = pch_dma_probe, .remove = pch_dma_remove, -#ifdef CONFIG_PM - .suspend = pch_dma_suspend, - .resume = pch_dma_resume, -#endif + .driver.pm = &pch_dma_pm_ops, }; module_pci_driver(pch_dma_driver); diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 5274a0704d96..000c3c4b4f7a 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -255,7 +255,7 @@ enum pl330_byteswap { static unsigned cmd_line; #define PL330_DBGCMD_DUMP(off, x...) do { \ printk("%x:", cmd_line); \ - printk(x); \ + printk(KERN_CONT x); \ cmd_line += off; \ } while (0) #define PL330_DBGMC_START(addr) (cmd_line = addr) @@ -460,9 +460,6 @@ struct pl330_dmac { /* DMA-Engine Device */ struct dma_device ddma; - /* Holds info about sg limitations */ - struct device_dma_parameters dma_parms; - /* Pool of descriptors available for the DMAC's channels */ struct list_head desc_pool; /* To protect desc_pool manipulation */ @@ -3034,9 +3031,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pl330->rstc = devm_reset_control_get_optional(&adev->dev, "dma"); if (IS_ERR(pl330->rstc)) { - if (PTR_ERR(pl330->rstc) != -EPROBE_DEFER) - dev_err(&adev->dev, "Failed to get reset!\n"); - return PTR_ERR(pl330->rstc); + return dev_err_probe(&adev->dev, PTR_ERR(pl330->rstc), "Failed to get reset!\n"); } else { ret = reset_control_deassert(pl330->rstc); if (ret) { @@ -3047,9 +3042,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pl330->rstc_ocp = devm_reset_control_get_optional(&adev->dev, "dma-ocp"); if (IS_ERR(pl330->rstc_ocp)) { - if (PTR_ERR(pl330->rstc_ocp) != -EPROBE_DEFER) - dev_err(&adev->dev, "Failed to get OCP reset!\n"); - return PTR_ERR(pl330->rstc_ocp); + return dev_err_probe(&adev->dev, PTR_ERR(pl330->rstc_ocp), + "Failed to get OCP reset!\n"); } else { ret = reset_control_deassert(pl330->rstc_ocp); if (ret) { @@ -3154,8 +3148,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) } } - adev->dev.dma_parms = &pl330->dma_parms; - /* * This is the limit for transfers with a buswidth of 1, larger * buswidths will have larger limits. diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index 5a08dd0d3388..773e60c82b20 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -381,7 +381,6 @@ struct bam_device { void __iomem *regs; struct device *dev; struct dma_device common; - struct device_dma_parameters dma_parms; struct bam_chan *channels; u32 num_channels; u32 num_ees; @@ -1316,7 +1315,6 @@ static int bam_dma_probe(struct platform_device *pdev) /* set max dma segment size */ bdev->common.dev = bdev->dev; - bdev->common.dev->dma_parms = &bdev->dma_parms; ret = dma_set_max_seg_size(bdev->common.dev, BAM_FIFO_SIZE); if (ret) { dev_err(bdev->dev, "cannot set maximum segment size\n"); diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c index 6e530dca6d9e..1e66c6990d81 100644 --- a/drivers/dma/sf-pdma/sf-pdma.c +++ b/drivers/dma/sf-pdma/sf-pdma.c @@ -284,7 +284,6 @@ static void sf_pdma_free_desc(struct virt_dma_desc *vdesc) static void sf_pdma_donebh_tasklet(unsigned long arg) { struct sf_pdma_chan *chan = (struct sf_pdma_chan *)arg; - struct sf_pdma_desc *desc = chan->desc; unsigned long flags; spin_lock_irqsave(&chan->lock, flags); @@ -295,7 +294,10 @@ static void sf_pdma_donebh_tasklet(unsigned long arg) } spin_unlock_irqrestore(&chan->lock, flags); - dmaengine_desc_get_callback_invoke(desc->async_tx, NULL); + spin_lock_irqsave(&chan->vchan.lock, flags); + list_del(&chan->desc->vdesc.node); + vchan_cookie_complete(&chan->desc->vdesc); + spin_unlock_irqrestore(&chan->vchan.lock, flags); } static void sf_pdma_errbh_tasklet(unsigned long arg) @@ -332,8 +334,7 @@ static irqreturn_t sf_pdma_done_isr(int irq, void *dev_id) residue = readq(regs->residue); if (!residue) { - list_del(&chan->desc->vdesc.node); - vchan_cookie_complete(&chan->desc->vdesc); + tasklet_hi_schedule(&chan->done_tasklet); } else { /* submit next trascatioin if possible */ struct sf_pdma_desc *desc = chan->desc; @@ -347,8 +348,6 @@ static irqreturn_t sf_pdma_done_isr(int irq, void *dev_id) spin_unlock_irqrestore(&chan->vchan.lock, flags); - tasklet_hi_schedule(&chan->done_tasklet); - return IRQ_HANDLED; } diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig index 54d5d0369d3c..13437323a85b 100644 --- a/drivers/dma/sh/Kconfig +++ b/drivers/dma/sh/Kconfig @@ -32,12 +32,12 @@ config SH_DMAE Enable support for the Renesas SuperH DMA controllers. config RCAR_DMAC - tristate "Renesas R-Car Gen2 DMA Controller" + tristate "Renesas R-Car Gen{2,3} and RZ/G{1,2} DMA Controller" depends on ARCH_RENESAS || COMPILE_TEST select RENESAS_DMA help This driver supports the general purpose DMA controller found in the - Renesas R-Car second generation SoCs. + Renesas R-Car Gen{2,3} and RZ/G{1,2} SoCs. config RENESAS_USB_DMAC tristate "Renesas USB-DMA Controller" diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 59b36ab5d684..4b8a876adedb 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -199,7 +199,6 @@ struct rcar_dmac { struct dma_device engine; struct device *dev; void __iomem *iomem; - struct device_dma_parameters parms; unsigned int n_channels; struct rcar_dmac_chan *channels; @@ -1845,7 +1844,6 @@ static int rcar_dmac_probe(struct platform_device *pdev) dmac->dev = &pdev->dev; platform_set_drvdata(pdev, dmac); - dmac->dev->dma_parms = &dmac->parms; dma_set_max_seg_size(dmac->dev, RCAR_DMATCR_MASK); dma_set_mask_and_coherent(dmac->dev, DMA_BIT_MASK(40)); diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 21e2f1d0c210..6b10d5c935a0 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -535,7 +535,6 @@ struct d40_gen_dmac { * mode" allocated physical channels. * @num_log_chans: The number of logical channels. Calculated from * num_phy_chans. - * @dma_parms: DMA parameters for the channel * @dma_both: dma_device channels that can do both memcpy and slave transfers. * @dma_slave: dma_device channels that can do only do slave transfers. * @dma_memcpy: dma_device channels that can do only do memcpy transfers. @@ -577,7 +576,6 @@ struct d40_base { int num_memcpy_chans; int num_phy_chans; int num_log_chans; - struct device_dma_parameters dma_parms; struct dma_device dma_both; struct dma_device dma_slave; struct dma_device dma_memcpy; @@ -3641,7 +3639,6 @@ static int __init d40_probe(struct platform_device *pdev) if (ret) goto destroy_cache; - base->dev->dma_parms = &base->dma_parms; ret = dma_set_max_seg_size(base->dev, STEDMA40_MAX_SEG_SIZE); if (ret) { d40_err(&pdev->dev, "Failed to set dma max seg size\n"); diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 96ad1b3d24c6..d0055d2f0b9a 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -1311,12 +1311,8 @@ static int stm32_dma_probe(struct platform_device *pdev) return PTR_ERR(dmadev->base); dmadev->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(dmadev->clk)) { - ret = PTR_ERR(dmadev->clk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Can't get clock\n"); - return ret; - } + if (IS_ERR(dmadev->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dmadev->clk), "Can't get clock\n"); ret = clk_prepare_enable(dmadev->clk); if (ret < 0) { diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c index 12f7637e13a1..a10ccd964376 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c @@ -252,12 +252,9 @@ static int stm32_dmamux_probe(struct platform_device *pdev) spin_lock_init(&stm32_dmamux->lock); stm32_dmamux->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(stm32_dmamux->clk)) { - ret = PTR_ERR(stm32_dmamux->clk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Missing clock controller\n"); - return ret; - } + if (IS_ERR(stm32_dmamux->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(stm32_dmamux->clk), + "Missing clock controller\n"); ret = clk_prepare_enable(stm32_dmamux->clk); if (ret < 0) { diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 5469563703d1..08cfbfab837b 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -1580,12 +1580,9 @@ static int stm32_mdma_probe(struct platform_device *pdev) return PTR_ERR(dmadev->base); dmadev->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(dmadev->clk)) { - ret = PTR_ERR(dmadev->clk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Missing clock controller\n"); - return ret; - } + if (IS_ERR(dmadev->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dmadev->clk), + "Missing clock controller\n"); ret = clk_prepare_enable(dmadev->clk); if (ret < 0) { diff --git a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile index 9a29a107e374..0c67254caee6 100644 --- a/drivers/dma/ti/Makefile +++ b/drivers/dma/ti/Makefile @@ -4,5 +4,8 @@ obj-$(CONFIG_TI_EDMA) += edma.o obj-$(CONFIG_DMA_OMAP) += omap-dma.o obj-$(CONFIG_TI_K3_UDMA) += k3-udma.o obj-$(CONFIG_TI_K3_UDMA_GLUE_LAYER) += k3-udma-glue.o -obj-$(CONFIG_TI_K3_PSIL) += k3-psil.o k3-psil-am654.o k3-psil-j721e.o +obj-$(CONFIG_TI_K3_PSIL) += k3-psil.o \ + k3-psil-am654.o \ + k3-psil-j721e.o \ + k3-psil-j7200.o obj-$(CONFIG_TI_DMA_CROSSBAR) += dma-crossbar.o diff --git a/drivers/dma/ti/k3-psil-j7200.c b/drivers/dma/ti/k3-psil-j7200.c new file mode 100644 index 000000000000..5ea63ea74822 --- /dev/null +++ b/drivers/dma/ti/k3-psil-j7200.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + * Author: Peter Ujfalusi <[email protected]> + */ + +#include <linux/kernel.h> + +#include "k3-psil-priv.h" + +#define PSIL_PDMA_XY_TR(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_PDMA_XY, \ + }, \ + } + +#define PSIL_PDMA_XY_PKT(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_PDMA_XY, \ + .pkt_mode = 1, \ + }, \ + } + +#define PSIL_PDMA_MCASP(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_PDMA_XY, \ + .pdma_acc32 = 1, \ + .pdma_burst = 1, \ + }, \ + } + +#define PSIL_ETHERNET(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + .pkt_mode = 1, \ + .needs_epib = 1, \ + .psd_size = 16, \ + }, \ + } + +#define PSIL_SA2UL(x, tx) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + .pkt_mode = 1, \ + .needs_epib = 1, \ + .psd_size = 64, \ + .notdpkt = tx, \ + }, \ + } + +/* PSI-L source thread IDs, used for RX (DMA_DEV_TO_MEM) */ +static struct psil_ep j7200_src_ep_map[] = { + /* PDMA_MCASP - McASP0-2 */ + PSIL_PDMA_MCASP(0x4400), + PSIL_PDMA_MCASP(0x4401), + PSIL_PDMA_MCASP(0x4402), + /* PDMA_SPI_G0 - SPI0-3 */ + PSIL_PDMA_XY_PKT(0x4600), + PSIL_PDMA_XY_PKT(0x4601), + PSIL_PDMA_XY_PKT(0x4602), + PSIL_PDMA_XY_PKT(0x4603), + PSIL_PDMA_XY_PKT(0x4604), + PSIL_PDMA_XY_PKT(0x4605), + PSIL_PDMA_XY_PKT(0x4606), + PSIL_PDMA_XY_PKT(0x4607), + PSIL_PDMA_XY_PKT(0x4608), + PSIL_PDMA_XY_PKT(0x4609), + PSIL_PDMA_XY_PKT(0x460a), + PSIL_PDMA_XY_PKT(0x460b), + PSIL_PDMA_XY_PKT(0x460c), + PSIL_PDMA_XY_PKT(0x460d), + PSIL_PDMA_XY_PKT(0x460e), + PSIL_PDMA_XY_PKT(0x460f), + /* PDMA_SPI_G1 - SPI4-7 */ + PSIL_PDMA_XY_PKT(0x4610), + PSIL_PDMA_XY_PKT(0x4611), + PSIL_PDMA_XY_PKT(0x4612), + PSIL_PDMA_XY_PKT(0x4613), + PSIL_PDMA_XY_PKT(0x4614), + PSIL_PDMA_XY_PKT(0x4615), + PSIL_PDMA_XY_PKT(0x4616), + PSIL_PDMA_XY_PKT(0x4617), + PSIL_PDMA_XY_PKT(0x4618), + PSIL_PDMA_XY_PKT(0x4619), + PSIL_PDMA_XY_PKT(0x461a), + PSIL_PDMA_XY_PKT(0x461b), + PSIL_PDMA_XY_PKT(0x461c), + PSIL_PDMA_XY_PKT(0x461d), + PSIL_PDMA_XY_PKT(0x461e), + PSIL_PDMA_XY_PKT(0x461f), + /* PDMA_USART_G0 - UART0-1 */ + PSIL_PDMA_XY_PKT(0x4700), + PSIL_PDMA_XY_PKT(0x4701), + /* PDMA_USART_G1 - UART2-3 */ + PSIL_PDMA_XY_PKT(0x4702), + PSIL_PDMA_XY_PKT(0x4703), + /* PDMA_USART_G2 - UART4-9 */ + PSIL_PDMA_XY_PKT(0x4704), + PSIL_PDMA_XY_PKT(0x4705), + PSIL_PDMA_XY_PKT(0x4706), + PSIL_PDMA_XY_PKT(0x4707), + PSIL_PDMA_XY_PKT(0x4708), + PSIL_PDMA_XY_PKT(0x4709), + /* CPSW5 */ + PSIL_ETHERNET(0x4a00), + /* CPSW0 */ + PSIL_ETHERNET(0x7000), + /* MCU_PDMA_MISC_G0 - SPI0 */ + PSIL_PDMA_XY_PKT(0x7100), + PSIL_PDMA_XY_PKT(0x7101), + PSIL_PDMA_XY_PKT(0x7102), + PSIL_PDMA_XY_PKT(0x7103), + /* MCU_PDMA_MISC_G1 - SPI1-2 */ + PSIL_PDMA_XY_PKT(0x7200), + PSIL_PDMA_XY_PKT(0x7201), + PSIL_PDMA_XY_PKT(0x7202), + PSIL_PDMA_XY_PKT(0x7203), + PSIL_PDMA_XY_PKT(0x7204), + PSIL_PDMA_XY_PKT(0x7205), + PSIL_PDMA_XY_PKT(0x7206), + PSIL_PDMA_XY_PKT(0x7207), + /* MCU_PDMA_MISC_G2 - UART0 */ + PSIL_PDMA_XY_PKT(0x7300), + /* MCU_PDMA_ADC - ADC0-1 */ + PSIL_PDMA_XY_TR(0x7400), + PSIL_PDMA_XY_TR(0x7401), + /* SA2UL */ + PSIL_SA2UL(0x7500, 0), + PSIL_SA2UL(0x7501, 0), + PSIL_SA2UL(0x7502, 0), + PSIL_SA2UL(0x7503, 0), +}; + +/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */ +static struct psil_ep j7200_dst_ep_map[] = { + /* CPSW5 */ + PSIL_ETHERNET(0xca00), + PSIL_ETHERNET(0xca01), + PSIL_ETHERNET(0xca02), + PSIL_ETHERNET(0xca03), + PSIL_ETHERNET(0xca04), + PSIL_ETHERNET(0xca05), + PSIL_ETHERNET(0xca06), + PSIL_ETHERNET(0xca07), + /* CPSW0 */ + PSIL_ETHERNET(0xf000), + PSIL_ETHERNET(0xf001), + PSIL_ETHERNET(0xf002), + PSIL_ETHERNET(0xf003), + PSIL_ETHERNET(0xf004), + PSIL_ETHERNET(0xf005), + PSIL_ETHERNET(0xf006), + PSIL_ETHERNET(0xf007), + /* SA2UL */ + PSIL_SA2UL(0xf500, 1), + PSIL_SA2UL(0xf501, 1), +}; + +struct psil_ep_map j7200_ep_map = { + .name = "j7200", + .src = j7200_src_ep_map, + .src_count = ARRAY_SIZE(j7200_src_ep_map), + .dst = j7200_dst_ep_map, + .dst_count = ARRAY_SIZE(j7200_dst_ep_map), +}; diff --git a/drivers/dma/ti/k3-psil-j721e.c b/drivers/dma/ti/k3-psil-j721e.c index e3cfd5f66842..7580870ed746 100644 --- a/drivers/dma/ti/k3-psil-j721e.c +++ b/drivers/dma/ti/k3-psil-j721e.c @@ -166,6 +166,8 @@ static struct psil_ep j721e_src_ep_map[] = { /* SA2UL */ PSIL_SA2UL(0x7500, 0), PSIL_SA2UL(0x7501, 0), + PSIL_SA2UL(0x7502, 0), + PSIL_SA2UL(0x7503, 0), }; /* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */ @@ -211,6 +213,7 @@ static struct psil_ep j721e_dst_ep_map[] = { PSIL_ETHERNET(0xf007), /* SA2UL */ PSIL_SA2UL(0xf500, 1), + PSIL_SA2UL(0xf501, 1), }; struct psil_ep_map j721e_ep_map = { diff --git a/drivers/dma/ti/k3-psil-priv.h b/drivers/dma/ti/k3-psil-priv.h index a1f389ca371e..b4b0fb359eff 100644 --- a/drivers/dma/ti/k3-psil-priv.h +++ b/drivers/dma/ti/k3-psil-priv.h @@ -39,5 +39,6 @@ struct psil_endpoint_config *psil_get_ep_config(u32 thread_id); /* SoC PSI-L endpoint maps */ extern struct psil_ep_map am654_ep_map; extern struct psil_ep_map j721e_ep_map; +extern struct psil_ep_map j7200_ep_map; #endif /* K3_PSIL_PRIV_H_ */ diff --git a/drivers/dma/ti/k3-psil.c b/drivers/dma/ti/k3-psil.c index fb7c8150b0d1..837853aab95a 100644 --- a/drivers/dma/ti/k3-psil.c +++ b/drivers/dma/ti/k3-psil.c @@ -9,11 +9,19 @@ #include <linux/init.h> #include <linux/mutex.h> #include <linux/of.h> +#include <linux/sys_soc.h> #include "k3-psil-priv.h" static DEFINE_MUTEX(ep_map_mutex); -static struct psil_ep_map *soc_ep_map; +static const struct psil_ep_map *soc_ep_map; + +static const struct soc_device_attribute k3_soc_devices[] = { + { .family = "AM65X", .data = &am654_ep_map }, + { .family = "J721E", .data = &j721e_ep_map }, + { .family = "J7200", .data = &j7200_ep_map }, + { /* sentinel */ } +}; struct psil_endpoint_config *psil_get_ep_config(u32 thread_id) { @@ -21,10 +29,11 @@ struct psil_endpoint_config *psil_get_ep_config(u32 thread_id) mutex_lock(&ep_map_mutex); if (!soc_ep_map) { - if (of_machine_is_compatible("ti,am654")) { - soc_ep_map = &am654_ep_map; - } else if (of_machine_is_compatible("ti,j721e")) { - soc_ep_map = &j721e_ep_map; + const struct soc_device_attribute *soc; + + soc = soc_device_match(k3_soc_devices); + if (soc) { + soc_ep_map = soc->data; } else { pr_err("PSIL: No compatible machine found for map\n"); mutex_unlock(&ep_map_mutex); diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c index 3a5d33ea5ebe..42c8ad10d75e 100644 --- a/drivers/dma/ti/k3-udma-glue.c +++ b/drivers/dma/ti/k3-udma-glue.c @@ -378,17 +378,11 @@ EXPORT_SYMBOL_GPL(k3_udma_glue_pop_tx_chn); int k3_udma_glue_enable_tx_chn(struct k3_udma_glue_tx_channel *tx_chn) { - u32 txrt_ctl; - - txrt_ctl = UDMA_PEER_RT_EN_ENABLE; xudma_tchanrt_write(tx_chn->udma_tchanx, UDMA_CHAN_RT_PEER_RT_EN_REG, - txrt_ctl); + UDMA_PEER_RT_EN_ENABLE); - txrt_ctl = xudma_tchanrt_read(tx_chn->udma_tchanx, - UDMA_CHAN_RT_CTL_REG); - txrt_ctl |= UDMA_CHAN_RT_CTL_EN; xudma_tchanrt_write(tx_chn->udma_tchanx, UDMA_CHAN_RT_CTL_REG, - txrt_ctl); + UDMA_CHAN_RT_CTL_EN); k3_udma_glue_dump_tx_rt_chn(tx_chn, "txchn en"); return 0; @@ -1058,19 +1052,14 @@ EXPORT_SYMBOL_GPL(k3_udma_glue_rx_flow_disable); int k3_udma_glue_enable_rx_chn(struct k3_udma_glue_rx_channel *rx_chn) { - u32 rxrt_ctl; - if (rx_chn->remote) return -EINVAL; if (rx_chn->flows_ready < rx_chn->flow_num) return -EINVAL; - rxrt_ctl = xudma_rchanrt_read(rx_chn->udma_rchanx, - UDMA_CHAN_RT_CTL_REG); - rxrt_ctl |= UDMA_CHAN_RT_CTL_EN; xudma_rchanrt_write(rx_chn->udma_rchanx, UDMA_CHAN_RT_CTL_REG, - rxrt_ctl); + UDMA_CHAN_RT_CTL_EN); xudma_rchanrt_write(rx_chn->udma_rchanx, UDMA_CHAN_RT_PEER_RT_EN_REG, UDMA_PEER_RT_EN_ENABLE); diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index d86dba0fd8e6..de7bfc02a2de 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/sys_soc.h> #include <linux/of.h> #include <linux/of_dma.h> #include <linux/of_device.h> @@ -91,6 +92,9 @@ struct udma_match_data { bool enable_memcpy_support; u32 flags; u32 statictr_z_mask; +}; + +struct udma_soc_data { u32 rchan_oes_offset; }; @@ -117,6 +121,7 @@ struct udma_dev { struct device *dev; void __iomem *mmrs[MMR_LAST]; const struct udma_match_data *match_data; + const struct udma_soc_data *soc_data; u8 tpl_levels; u32 tpl_start_idx[3]; @@ -1679,7 +1684,7 @@ static int udma_alloc_chan_resources(struct dma_chan *chan) { struct udma_chan *uc = to_udma_chan(chan); struct udma_dev *ud = to_udma_dev(chan->device); - const struct udma_match_data *match_data = ud->match_data; + const struct udma_soc_data *soc_data = ud->soc_data; struct k3_ring *irq_ring; u32 irq_udma_idx; int ret; @@ -1779,7 +1784,7 @@ static int udma_alloc_chan_resources(struct dma_chan *chan) K3_PSIL_DST_THREAD_ID_OFFSET; irq_ring = uc->rflow->r_ring; - irq_udma_idx = match_data->rchan_oes_offset + uc->rchan->id; + irq_udma_idx = soc_data->rchan_oes_offset + uc->rchan->id; ret = udma_tisci_rx_channel_config(uc); break; @@ -2024,11 +2029,6 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, int num_tr = 0; int tr_idx = 0; - if (!is_slave_direction(dir)) { - dev_err(uc->ud->dev, "Only slave cyclic is supported\n"); - return NULL; - } - /* estimate the number of TRs we will need */ for_each_sg(sgl, sgent, sglen, i) { if (sg_dma_len(sgent) < SZ_64K) @@ -2400,11 +2400,6 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, unsigned int i; int num_tr; - if (!is_slave_direction(dir)) { - dev_err(uc->ud->dev, "Only slave cyclic is supported\n"); - return NULL; - } - num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0, &tr0_cnt1, &tr1_cnt0); if (num_tr < 0) { @@ -3101,14 +3096,12 @@ static struct udma_match_data am654_main_data = { .psil_base = 0x1000, .enable_memcpy_support = true, .statictr_z_mask = GENMASK(11, 0), - .rchan_oes_offset = 0x200, }; static struct udma_match_data am654_mcu_data = { .psil_base = 0x6000, .enable_memcpy_support = false, .statictr_z_mask = GENMASK(11, 0), - .rchan_oes_offset = 0x200, }; static struct udma_match_data j721e_main_data = { @@ -3116,7 +3109,6 @@ static struct udma_match_data j721e_main_data = { .enable_memcpy_support = true, .flags = UDMA_FLAG_PDMA_ACC32 | UDMA_FLAG_PDMA_BURST, .statictr_z_mask = GENMASK(23, 0), - .rchan_oes_offset = 0x400, }; static struct udma_match_data j721e_mcu_data = { @@ -3124,7 +3116,6 @@ static struct udma_match_data j721e_mcu_data = { .enable_memcpy_support = false, /* MEM_TO_MEM is slow via MCU UDMA */ .flags = UDMA_FLAG_PDMA_ACC32 | UDMA_FLAG_PDMA_BURST, .statictr_z_mask = GENMASK(23, 0), - .rchan_oes_offset = 0x400, }; static const struct of_device_id udma_of_match[] = { @@ -3145,6 +3136,25 @@ static const struct of_device_id udma_of_match[] = { { /* Sentinel */ }, }; +static struct udma_soc_data am654_soc_data = { + .rchan_oes_offset = 0x200, +}; + +static struct udma_soc_data j721e_soc_data = { + .rchan_oes_offset = 0x400, +}; + +static struct udma_soc_data j7200_soc_data = { + .rchan_oes_offset = 0x80, +}; + +static const struct soc_device_attribute k3_soc_devices[] = { + { .family = "AM65X", .data = &am654_soc_data }, + { .family = "J721E", .data = &j721e_soc_data }, + { .family = "J7200", .data = &j7200_soc_data }, + { /* sentinel */ } +}; + static int udma_get_mmrs(struct platform_device *pdev, struct udma_dev *ud) { struct resource *res; @@ -3287,7 +3297,7 @@ static int udma_setup_resources(struct udma_dev *ud) rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN]; for (j = 0; j < rm_res->sets; j++, i++) { irq_res.desc[i].start = rm_res->desc[j].start + - ud->match_data->rchan_oes_offset; + ud->soc_data->rchan_oes_offset; irq_res.desc[i].num = rm_res->desc[j].num; } ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res); @@ -3497,6 +3507,7 @@ static void udma_dbg_summary_show(struct seq_file *s, static int udma_probe(struct platform_device *pdev) { struct device_node *navss_node = pdev->dev.parent->of_node; + const struct soc_device_attribute *soc; struct device *dev = &pdev->dev; struct udma_dev *ud; const struct of_device_id *match; @@ -3561,6 +3572,13 @@ static int udma_probe(struct platform_device *pdev) } ud->match_data = match->data; + soc = soc_device_match(k3_soc_devices); + if (!soc) { + dev_err(dev, "No compatible SoC found\n"); + return -ENODEV; + } + ud->soc_data = soc->data; + dma_cap_set(DMA_SLAVE, ud->ddev.cap_mask); dma_cap_set(DMA_CYCLIC, ud->ddev.cap_mask); diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index 918301e17552..c9fe5e3a6b55 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -1904,7 +1904,7 @@ static struct platform_driver omap_dma_driver = { .remove = omap_dma_remove, .driver = { .name = "omap-dma-engine", - .of_match_table = of_match_ptr(omap_dma_match), + .of_match_table = omap_dma_match, }, }; diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 5429497d3560..286cf94a950d 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -2536,13 +2536,8 @@ static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk, *tmp_clk = NULL; *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); - if (IS_ERR(*axi_clk)) { - err = PTR_ERR(*axi_clk); - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get axi_aclk (%d)\n", - err); - return err; - } + if (IS_ERR(*axi_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(*axi_clk), "failed to get axi_aclk\n"); *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk"); if (IS_ERR(*tx_clk)) @@ -2603,22 +2598,12 @@ static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk, *tmp2_clk = NULL; *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); - if (IS_ERR(*axi_clk)) { - err = PTR_ERR(*axi_clk); - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get axi_clk (%d)\n", - err); - return err; - } + if (IS_ERR(*axi_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(*axi_clk), "failed to get axi_aclk\n"); *dev_clk = devm_clk_get(&pdev->dev, "m_axi_aclk"); - if (IS_ERR(*dev_clk)) { - err = PTR_ERR(*dev_clk); - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get dev_clk (%d)\n", - err); - return err; - } + if (IS_ERR(*dev_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(*dev_clk), "failed to get dev_clk\n"); err = clk_prepare_enable(*axi_clk); if (err) { @@ -2647,13 +2632,8 @@ static int axivdma_clk_init(struct platform_device *pdev, struct clk **axi_clk, int err; *axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk"); - if (IS_ERR(*axi_clk)) { - err = PTR_ERR(*axi_clk); - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get axi_aclk (%d)\n", - err); - return err; - } + if (IS_ERR(*axi_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(*axi_clk), "failed to get axi_aclk\n"); *tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk"); if (IS_ERR(*tx_clk)) diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c index b37197c772aa..81ed1e482878 100644 --- a/drivers/dma/xilinx/xilinx_dpdma.c +++ b/drivers/dma/xilinx/xilinx_dpdma.c @@ -10,6 +10,7 @@ #include <linux/bitfield.h> #include <linux/bits.h> #include <linux/clk.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dmaengine.h> #include <linux/dmapool.h> @@ -267,6 +268,210 @@ struct xilinx_dpdma_device { }; /* ----------------------------------------------------------------------------- + * DebugFS + */ + +#ifdef CONFIG_DEBUG_FS + +#define XILINX_DPDMA_DEBUGFS_READ_MAX_SIZE 32 +#define XILINX_DPDMA_DEBUGFS_UINT16_MAX_STR "65535" + +/* Match xilinx_dpdma_testcases vs dpdma_debugfs_reqs[] entry */ +enum xilinx_dpdma_testcases { + DPDMA_TC_INTR_DONE, + DPDMA_TC_NONE +}; + +struct xilinx_dpdma_debugfs { + enum xilinx_dpdma_testcases testcase; + u16 xilinx_dpdma_irq_done_count; + unsigned int chan_id; +}; + +static struct xilinx_dpdma_debugfs dpdma_debugfs; +struct xilinx_dpdma_debugfs_request { + const char *name; + enum xilinx_dpdma_testcases tc; + ssize_t (*read)(char *buf); + int (*write)(char *args); +}; + +static void xilinx_dpdma_debugfs_desc_done_irq(struct xilinx_dpdma_chan *chan) +{ + if (chan->id == dpdma_debugfs.chan_id) + dpdma_debugfs.xilinx_dpdma_irq_done_count++; +} + +static ssize_t xilinx_dpdma_debugfs_desc_done_irq_read(char *buf) +{ + size_t out_str_len; + + dpdma_debugfs.testcase = DPDMA_TC_NONE; + + out_str_len = strlen(XILINX_DPDMA_DEBUGFS_UINT16_MAX_STR); + out_str_len = min_t(size_t, XILINX_DPDMA_DEBUGFS_READ_MAX_SIZE, + out_str_len); + snprintf(buf, out_str_len, "%d", + dpdma_debugfs.xilinx_dpdma_irq_done_count); + + return 0; +} + +static int xilinx_dpdma_debugfs_desc_done_irq_write(char *args) +{ + char *arg; + int ret; + u32 id; + + arg = strsep(&args, " "); + if (!arg || strncasecmp(arg, "start", 5)) + return -EINVAL; + + arg = strsep(&args, " "); + if (!arg) + return -EINVAL; + + ret = kstrtou32(arg, 0, &id); + if (ret < 0) + return ret; + + if (id < ZYNQMP_DPDMA_VIDEO0 || id > ZYNQMP_DPDMA_AUDIO1) + return -EINVAL; + + dpdma_debugfs.testcase = DPDMA_TC_INTR_DONE; + dpdma_debugfs.xilinx_dpdma_irq_done_count = 0; + dpdma_debugfs.chan_id = id; + + return 0; +} + +/* Match xilinx_dpdma_testcases vs dpdma_debugfs_reqs[] entry */ +static struct xilinx_dpdma_debugfs_request dpdma_debugfs_reqs[] = { + { + .name = "DESCRIPTOR_DONE_INTR", + .tc = DPDMA_TC_INTR_DONE, + .read = xilinx_dpdma_debugfs_desc_done_irq_read, + .write = xilinx_dpdma_debugfs_desc_done_irq_write, + }, +}; + +static ssize_t xilinx_dpdma_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + enum xilinx_dpdma_testcases testcase; + char *kern_buff; + int ret = 0; + + if (*pos != 0 || size <= 0) + return -EINVAL; + + kern_buff = kzalloc(XILINX_DPDMA_DEBUGFS_READ_MAX_SIZE, GFP_KERNEL); + if (!kern_buff) { + dpdma_debugfs.testcase = DPDMA_TC_NONE; + return -ENOMEM; + } + + testcase = READ_ONCE(dpdma_debugfs.testcase); + if (testcase != DPDMA_TC_NONE) { + ret = dpdma_debugfs_reqs[testcase].read(kern_buff); + if (ret < 0) + goto done; + } else { + strlcpy(kern_buff, "No testcase executed", + XILINX_DPDMA_DEBUGFS_READ_MAX_SIZE); + } + + size = min(size, strlen(kern_buff)); + if (copy_to_user(buf, kern_buff, size)) + ret = -EFAULT; + +done: + kfree(kern_buff); + if (ret) + return ret; + + *pos = size + 1; + return size; +} + +static ssize_t xilinx_dpdma_debugfs_write(struct file *f, + const char __user *buf, size_t size, + loff_t *pos) +{ + char *kern_buff, *kern_buff_start; + char *testcase; + unsigned int i; + int ret; + + if (*pos != 0 || size <= 0) + return -EINVAL; + + /* Supporting single instance of test as of now. */ + if (dpdma_debugfs.testcase != DPDMA_TC_NONE) + return -EBUSY; + + kern_buff = kzalloc(size, GFP_KERNEL); + if (!kern_buff) + return -ENOMEM; + kern_buff_start = kern_buff; + + ret = strncpy_from_user(kern_buff, buf, size); + if (ret < 0) + goto done; + + /* Read the testcase name from a user request. */ + testcase = strsep(&kern_buff, " "); + + for (i = 0; i < ARRAY_SIZE(dpdma_debugfs_reqs); i++) { + if (!strcasecmp(testcase, dpdma_debugfs_reqs[i].name)) + break; + } + + if (i == ARRAY_SIZE(dpdma_debugfs_reqs)) { + ret = -EINVAL; + goto done; + } + + ret = dpdma_debugfs_reqs[i].write(kern_buff); + if (ret < 0) + goto done; + + ret = size; + +done: + kfree(kern_buff_start); + return ret; +} + +static const struct file_operations fops_xilinx_dpdma_dbgfs = { + .owner = THIS_MODULE, + .read = xilinx_dpdma_debugfs_read, + .write = xilinx_dpdma_debugfs_write, +}; + +static void xilinx_dpdma_debugfs_init(struct xilinx_dpdma_device *xdev) +{ + struct dentry *dent; + + dpdma_debugfs.testcase = DPDMA_TC_NONE; + + dent = debugfs_create_file("testcase", 0444, xdev->common.dbg_dev_root, + NULL, &fops_xilinx_dpdma_dbgfs); + if (IS_ERR(dent)) + dev_err(xdev->dev, "Failed to create debugfs testcase file\n"); +} + +#else +static void xilinx_dpdma_debugfs_init(struct xilinx_dpdma_device *xdev) +{ +} + +static void xilinx_dpdma_debugfs_desc_done_irq(struct xilinx_dpdma_chan *chan) +{ +} +#endif /* CONFIG_DEBUG_FS */ + +/* ----------------------------------------------------------------------------- * I/O Accessors */ @@ -842,6 +1047,8 @@ static void xilinx_dpdma_chan_done_irq(struct xilinx_dpdma_chan *chan) spin_lock_irqsave(&chan->lock, flags); + xilinx_dpdma_debugfs_desc_done_irq(chan); + if (active) vchan_cyclic_callback(&active->vdesc); else @@ -1477,6 +1684,8 @@ static int xilinx_dpdma_probe(struct platform_device *pdev) xilinx_dpdma_enable_irq(xdev); + xilinx_dpdma_debugfs_init(xdev); + dev_info(&pdev->dev, "Xilinx DPDMA engine is probed\n"); return 0; diff --git a/drivers/dma/zx_dma.c b/drivers/dma/zx_dma.c index 5fe2e8b9a7b8..b057582b2fac 100644 --- a/drivers/dma/zx_dma.c +++ b/drivers/dma/zx_dma.c @@ -285,9 +285,7 @@ static irqreturn_t zx_dma_int_handler(int irq, void *dev_id) p = &d->phy[i]; c = p->vchan; if (c) { - unsigned long flags; - - spin_lock_irqsave(&c->vc.lock, flags); + spin_lock(&c->vc.lock); if (c->cyclic) { vchan_cyclic_callback(&p->ds_run->vd); } else { @@ -295,7 +293,7 @@ static irqreturn_t zx_dma_int_handler(int irq, void *dev_id) p->ds_done = p->ds_run; task = 1; } - spin_unlock_irqrestore(&c->vc.lock, flags); + spin_unlock(&c->vc.lock); irq_chan |= BIT(i); } } diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 6fbd5c99e30c..dd357a747780 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -1472,7 +1472,6 @@ void dma_issue_pending_all(void); struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param, struct device_node *np); -struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name); struct dma_chan *dma_request_chan(struct device *dev, const char *name); struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask); @@ -1502,11 +1501,6 @@ static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, { return NULL; } -static inline struct dma_chan *dma_request_slave_channel(struct device *dev, - const char *name) -{ - return NULL; -} static inline struct dma_chan *dma_request_chan(struct device *dev, const char *name) { @@ -1527,8 +1521,6 @@ static inline int dma_get_slave_caps(struct dma_chan *chan, } #endif -#define dma_request_slave_channel_reason(dev, name) dma_request_chan(dev, name) - static inline int dmaengine_desc_set_reuse(struct dma_async_tx_descriptor *tx) { struct dma_slave_caps caps; @@ -1577,6 +1569,15 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx); #define dma_request_channel(mask, x, y) \ __dma_request_channel(&(mask), x, y, NULL) +/* Deprecated, please use dma_request_chan() directly */ +static inline struct dma_chan * __deprecated +dma_request_slave_channel(struct device *dev, const char *name) +{ + struct dma_chan *ch = dma_request_chan(dev, name); + + return IS_ERR(ch) ? NULL : ch; +} + static inline struct dma_chan *dma_request_slave_channel_compat(const dma_cap_mask_t mask, dma_filter_fn fn, void *fn_param, diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h index fbbeb2f6189b..b34a094b2258 100644 --- a/include/linux/platform_data/dma-dw.h +++ b/include/linux/platform_data/dma-dw.h @@ -26,6 +26,7 @@ struct device; * @dst_id: dst request line * @m_master: memory master for transfers on allocated channel * @p_master: peripheral master for transfers on allocated channel + * @channels: mask of the channels permitted for allocation (zero value means any) * @hs_polarity:set active low polarity of handshake interface */ struct dw_dma_slave { @@ -34,6 +35,7 @@ struct dw_dma_slave { u8 dst_id; u8 m_master; u8 p_master; + u8 channels; bool hs_polarity; }; |