* [PATCH v1 0/5] dma: Add QorIQ qDMA engine driver support
@ 2016-08-18 6:38 Yuan Yao
2016-08-18 6:38 ` [PATCH v1 1/5] " Yuan Yao
` (4 more replies)
0 siblings, 5 replies; 14+ messages in thread
From: Yuan Yao @ 2016-08-18 6:38 UTC (permalink / raw)
To: vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo
Cc: leoyang.li, dmaengine, linux-kernel, linux-arm-kernel, Yuan Yao
From: Yuan Yao <yao.yuan@nxp.com>
dma: Add QorIQ qDMA engine driver support
Yuan Yao (5):
dma: Add QorIQ qDMA engine driver support
dma: Add device tree binding for QorIQ qDMA driver
MAINTAINERS: add maintainer entry for QorIQ QDMA driver
ARM: dts: ls1043a: add qDMA node
ARM: dts: ls1021a: add qDMA node
.../devicetree/bindings/dma/qoriq-qdma.txt | 38 +
MAINTAINERS | 7 +
arch/arm/boot/dts/ls1021a.dtsi | 10 +
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 10 +
drivers/dma/Kconfig | 12 +
drivers/dma/Makefile | 1 +
drivers/dma/qoriq-qdma.c | 900 +++++++++++++++++++++
drivers/dma/qoriq-qdma.h | 272 +++++++
8 files changed, 1250 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/qoriq-qdma.txt
create mode 100644 drivers/dma/qoriq-qdma.c
create mode 100644 drivers/dma/qoriq-qdma.h
--
2.1.0.27.g96db324
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v1 1/5] dma: Add QorIQ qDMA engine driver support 2016-08-18 6:38 [PATCH v1 0/5] dma: Add QorIQ qDMA engine driver support Yuan Yao @ 2016-08-18 6:38 ` Yuan Yao 2016-08-18 9:16 ` Russell King - ARM Linux ` (2 more replies) 2016-08-18 6:38 ` [PATCH v1 2/5] dma: Add device tree binding for QorIQ qDMA driver Yuan Yao ` (3 subsequent siblings) 4 siblings, 3 replies; 14+ messages in thread From: Yuan Yao @ 2016-08-18 6:38 UTC (permalink / raw) To: vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo Cc: leoyang.li, dmaengine, linux-kernel, linux-arm-kernel, Yuan Yao From: Yuan Yao <yao.yuan@nxp.com> Add QorIQ queue direct memory access(QDMA) controller support. This module can be found on QorIQ LS1021A and LS1043A SoCs. Signed-off-by: Yuan Yao <yao.yuan@nxp.com> --- drivers/dma/Kconfig | 12 + drivers/dma/Makefile | 1 + drivers/dma/qoriq-qdma.c | 900 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/dma/qoriq-qdma.h | 272 ++++++++++++++ 4 files changed, 1185 insertions(+) create mode 100644 drivers/dma/qoriq-qdma.c create mode 100644 drivers/dma/qoriq-qdma.h diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 739f797..a1d8c05 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -193,6 +193,18 @@ config FSL_EDMA multiplexing capability for DMA request sources(slot). This module can be found on Freescale Vybrid and LS-1 SoCs. +config QORIQ_QDMA + tristate "QorIQ qDMA engine support" + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + select DMA_ENGINE_RAID + select ASYNC_TX_ENABLE_CHANNEL_SWITCH + help + Support the QorIQ qDMA engine with command queue mode. + Channel virtualization is supported through enqueuing of DMA jobs to, + or dequeuing DMA jobs from, different work queues. + This module can be found on some QorIQ SoCs. + config FSL_RAID tristate "Freescale RAID engine Support" depends on FSL_SOC && !ASYNC_TX_ENABLE_CHANNEL_SWITCH diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index e4dc9ca..9c8d0a7 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_DW_DMAC_CORE) += dw/ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_FSL_DMA) += fsldma.o obj-$(CONFIG_FSL_EDMA) += fsl-edma.o +obj-$(CONFIG_QORIQ_QDMA) += qoriq-qdma.o obj-$(CONFIG_FSL_RAID) += fsl_raid.o obj-$(CONFIG_HSU_DMA) += hsu/ obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o diff --git a/drivers/dma/qoriq-qdma.c b/drivers/dma/qoriq-qdma.c new file mode 100644 index 0000000..53d8809 --- /dev/null +++ b/drivers/dma/qoriq-qdma.c @@ -0,0 +1,900 @@ +/* + * drivers/dma/qoriq-qdma.c + * + * Copyright 2015-2016 NXP Semiconductor, Inc. + * + * Driver for the QorIQ qDMA engine with software command queue mode. + * Channel virtualization is supported through enqueuing of DMA jobs to, + * or dequeuing DMA jobs from, different work queues. + * This module can be found on some QorIQ SoCs. + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <asm/cacheflush.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_dma.h> +#include <linux/of_irq.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include "qoriq-qdma.h" + +static unsigned int channels = 2; +module_param(channels, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(channels, "Number of channels supported by driver"); + +static unsigned int status_sizes[FSL_QDMA_MAX_BLOCK], status_num; +module_param_array(status_sizes, uint, &status_num, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(status_sizes, "Size of each status queue in bytes"); + +static unsigned int queue_sizes[FSL_QDMA_MAX_QUEUE], queue_num; +module_param_array(queue_sizes, uint, &queue_num, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(queue_sizes, "Size of each command queue in bytes"); + +static void fsl_qdma_free_chan_resources(struct dma_chan *chan) +{ + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + vchan_get_all_descriptors(&fsl_chan->vchan, &head); + spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); + + vchan_dma_desc_free_list(&fsl_chan->vchan, &head); +} + +static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp, + dma_addr_t dst, dma_addr_t src, u32 len) +{ + struct fsl_qdma_frame *frame; + + memset(fsl_comp->virt_addr, 0, FSL_QDMA_BASE_BUFFER_SIZE); + frame = (struct fsl_qdma_frame *)fsl_comp->virt_addr; + /* Head Command Descriptor(Frame Descriptor) */ + frame->ccdf.addr_low = lower_32_bits(fsl_comp->bus_addr + 16); + frame->ccdf.dd_q_addr_high = (upper_32_bits(fsl_comp->bus_addr + 16)) + & QDMA_CCDF_ADDR_HIGH_MASK; + /* Compound S/G format */ + frame->ccdf.format_offset = (0 << QDMA_CCDF_OFFSET_SHIFT) | + (0x1 << QDMA_CCDF_FORMAT_SHIFT); + /* Status notification is enqueued to status queue. */ + frame->ccdf.ser_status = QDMA_CCDF_SER; + + /* Compound Command Descriptor(Frame List Table) */ + frame->csgf_desc.addr_low = lower_32_bits(fsl_comp->bus_addr + 64); + frame->csgf_desc.addr_high = upper_32_bits(fsl_comp->bus_addr + 64); + /* It must be 32 as Compound S/G Descriptor */ + frame->csgf_desc.e_f_length = 32; + frame->csgf_src.addr_low = lower_32_bits(src); + frame->csgf_src.addr_high = upper_32_bits(src); + frame->csgf_src.e_f_length = len; + frame->csgf_dest.addr_low = lower_32_bits(dst); + frame->csgf_dest.addr_high = upper_32_bits(dst); + frame->csgf_dest.e_f_length = len; + /* This entry is the last entry. */ + frame->csgf_dest.e_f_length |= QDMA_CSGF_F; + /* Descriptor Buffer */ + frame->sdf.cmd = FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET; + frame->ddf.cmd = FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET; +} + +static void fsl_qdma_comp_fill_sg( + struct fsl_qdma_comp *fsl_comp, + struct scatterlist *dst_sg, unsigned int dst_nents, + struct scatterlist *src_sg, unsigned int src_nents) +{ + struct fsl_qdma_csgf *csgf_sg; + struct fsl_qdma_sg *sg_block, *temp; + struct scatterlist *sg; + struct fsl_qdma_frame *frame; + dma_addr_t dma_address; + u64 total_src_len = 0; + u64 total_dst_len = 0; + u32 i; + + memset(fsl_comp->virt_addr, 0, FSL_QDMA_BASE_BUFFER_SIZE); + frame = (struct fsl_qdma_frame *)fsl_comp->virt_addr; + /* Head Command Descriptor(Frame Descriptor) */ + frame->ccdf.addr_low = lower_32_bits(fsl_comp->bus_addr + 16); + frame->ccdf.dd_q_addr_high = (upper_32_bits(fsl_comp->bus_addr + 16)) + & QDMA_CCDF_ADDR_HIGH_MASK; + /* Compound S/G format */ + frame->ccdf.format_offset |= 0x1 << QDMA_CCDF_FORMAT_SHIFT; + /* Status notification is enqueued to status queue. */ + frame->ccdf.ser_status |= QDMA_CCDF_SER; + + /* Compound Command Descriptor(Frame List Table) */ + frame->csgf_desc.addr_low = lower_32_bits(fsl_comp->bus_addr + 64); + frame->csgf_desc.addr_high = upper_32_bits(fsl_comp->bus_addr + 64); + /* It must be 32 as Compound S/G Descriptor */ + frame->csgf_desc.e_f_length = 32; + + sg_block = fsl_comp->sg_block; + frame->csgf_src.addr_low = lower_32_bits(sg_block->bus_addr); + frame->csgf_src.addr_high = upper_32_bits(sg_block->bus_addr); + /* This entry link to the s/g entry. */ + frame->csgf_src.e_f_length |= QDMA_CSGF_E; + + temp = sg_block + fsl_comp->sg_block_src; + frame->csgf_dest.addr_low = lower_32_bits(temp->bus_addr); + frame->csgf_dest.addr_high = upper_32_bits(temp->bus_addr); + /* This entry is the last entry and link to the s/g entry. */ + frame->csgf_dest.e_f_length |= QDMA_CSGF_F | QDMA_CSGF_E; + + for_each_sg(src_sg, sg, src_nents, i) { + temp = sg_block + i / (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1); + csgf_sg = (struct fsl_qdma_csgf *)temp->virt_addr + + i % (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1); + dma_address = sg_dma_address(sg); + csgf_sg->addr_low = lower_32_bits(dma_address); + csgf_sg->addr_high = upper_32_bits(dma_address); + csgf_sg->e_f_length |= sg_dma_len(sg); + total_src_len += sg_dma_len(sg); + + if (i == src_nents - 1) + csgf_sg->e_f_length |= QDMA_CSGF_F; + if (i % (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) == + FSL_QDMA_EXPECT_SG_ENTRY_NUM - 2) { + csgf_sg = (struct fsl_qdma_csgf *)temp->virt_addr + + FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1; + temp = sg_block + + i / (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) + 1; + csgf_sg->addr_low = lower_32_bits(temp->bus_addr); + csgf_sg->addr_high = upper_32_bits(temp->bus_addr); + csgf_sg->e_f_length |= QDMA_CSGF_E; + } + } + + sg_block += fsl_comp->sg_block_src; + for_each_sg(dst_sg, sg, dst_nents, i) { + temp = sg_block + i / (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1); + csgf_sg = (struct fsl_qdma_csgf *)temp->virt_addr + + i % (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1); + dma_address = sg_dma_address(sg); + csgf_sg->addr_low = lower_32_bits(dma_address); + csgf_sg->addr_high = upper_32_bits(dma_address); + csgf_sg->e_f_length |= sg_dma_len(sg); + total_dst_len += sg_dma_len(sg); + + if (i == dst_nents - 1) + csgf_sg->e_f_length |= QDMA_CSGF_F; + if (i % (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) == + FSL_QDMA_EXPECT_SG_ENTRY_NUM - 2) { + csgf_sg = (struct fsl_qdma_csgf *)temp->virt_addr + + FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1; + temp = sg_block + + i / (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) + 1; + csgf_sg->addr_low = lower_32_bits(temp->bus_addr); + csgf_sg->addr_high = upper_32_bits(temp->bus_addr); + csgf_sg->e_f_length |= QDMA_CSGF_E; + } + } + + if (total_src_len != total_dst_len) + dev_err(&fsl_comp->qchan->vchan.chan.dev->device, + "The data length for src and dst isn't match.\n"); + + frame->csgf_src.e_f_length |= total_src_len; + frame->csgf_dest.e_f_length |= total_dst_len; + + /* Descriptor Buffer */ + frame->sdf.cmd = FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET; + frame->ddf.cmd = FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET; +} + +/* + * Request a command descriptor for enqueue. + */ +static struct fsl_qdma_comp *fsl_qdma_request_enqueue_desc( + struct fsl_qdma_chan *fsl_chan, + unsigned int dst_nents, + unsigned int src_nents) +{ + struct fsl_qdma_comp *comp_temp; + struct fsl_qdma_sg *sg_block; + struct fsl_qdma_queue *queue = fsl_chan->queue; + unsigned long flags; + unsigned int dst_sg_entry_block, src_sg_entry_block, sg_entry_total, i; + + spin_lock_irqsave(&queue->queue_lock, flags); + if (list_empty(&queue->comp_free)) { + spin_unlock_irqrestore(&queue->queue_lock, flags); + comp_temp = kzalloc(sizeof(*comp_temp), GFP_KERNEL); + if (!comp_temp) + return NULL; + comp_temp->virt_addr = dma_pool_alloc(queue->comp_pool, + GFP_NOWAIT, + &comp_temp->bus_addr); + if (!comp_temp->virt_addr) + return NULL; + } else { + comp_temp = list_first_entry(&queue->comp_free, + struct fsl_qdma_comp, + list); + list_del(&comp_temp->list); + spin_unlock_irqrestore(&queue->queue_lock, flags); + } + + if (dst_nents != 0) + dst_sg_entry_block = dst_nents / + (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) + 1; + else + dst_sg_entry_block = 0; + + if (src_nents != 0) + src_sg_entry_block = src_nents / + (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) + 1; + else + src_sg_entry_block = 0; + + sg_entry_total = dst_sg_entry_block + src_sg_entry_block; + if (sg_entry_total) { + sg_block = kzalloc(sizeof(*sg_block) * + sg_entry_total, + GFP_KERNEL); + if (!sg_block) + return NULL; + comp_temp->sg_block = sg_block; + for (i = 0; i < sg_entry_total; i++) { + sg_block->virt_addr = dma_pool_alloc(queue->sg_pool, + GFP_NOWAIT, + &sg_block->bus_addr); + memset(sg_block->virt_addr, 0, + FSL_QDMA_EXPECT_SG_ENTRY_NUM * 16); + sg_block++; + } + } + + comp_temp->sg_block_src = src_sg_entry_block; + comp_temp->sg_block_dst = dst_sg_entry_block; + comp_temp->qchan = fsl_chan; + + return comp_temp; +} + +static struct fsl_qdma_queue *fsl_qdma_alloc_queue_resources( + struct platform_device *pdev, + enum qdma_queue_type type) +{ + struct fsl_qdma_queue *queue_head, *queue_temp; + unsigned int *qdma_queue_sizes, qdma_queue_num; + int len, i; + + if (type == QDMA_QUEUE) { + if (queue_num > FSL_QDMA_MAX_QUEUE) { + dev_warn(&pdev->dev, + "The max number of the queues is: %d\n", + FSL_QDMA_MAX_QUEUE); + queue_num = FSL_QDMA_MAX_QUEUE; + } + + if (queue_num == 0) { + dev_warn(&pdev->dev, + "The number of the queues can't be 0\n"); + queue_num = 1; + } + qdma_queue_sizes = queue_sizes; + qdma_queue_num = queue_num; + } else if (type == QDMA_STATUS) { + if (status_num > FSL_QDMA_MAX_BLOCK) { + dev_warn(&pdev->dev, + "The max number of the queues is: %d\n", + FSL_QDMA_MAX_BLOCK); + status_num = FSL_QDMA_MAX_BLOCK; + } + + if (status_num == 0) { + dev_warn(&pdev->dev, + "The number of the queues can't be 0\n"); + status_num = 1; + } + qdma_queue_sizes = status_sizes; + qdma_queue_num = status_num; + } else { + return NULL; + } + + len = sizeof(*queue_head) * qdma_queue_num; + queue_head = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!queue_head) + return NULL; + + for (i = 0; i < qdma_queue_num; i++) { + if (qdma_queue_sizes[i] > FSL_QDMA_CIRCULAR_SIZE_MAX + || qdma_queue_sizes[i] < FSL_QDMA_CIRCULAR_SIZE_MIN) { + dev_warn(&pdev->dev, "The wrong queue sizes\n"); + qdma_queue_sizes[i] = FSL_QDMA_CIRCULAR_SIZE_MIN; + } + queue_temp = queue_head + i; + queue_temp->cq = dma_alloc_coherent(&pdev->dev, + sizeof(struct fsl_qdma_ccdf) * + qdma_queue_sizes[i], + &queue_temp->bus_addr, + GFP_KERNEL); + if (!queue_temp->cq) + return NULL; + queue_temp->n_cq = qdma_queue_sizes[i]; + queue_temp->id = i; + queue_temp->virt_head = queue_temp->cq; + queue_temp->virt_tail = queue_temp->cq; + + /* + * There is no dma pool need for status queue. + */ + if (type == QDMA_STATUS) { + queue_temp->comp_pool = NULL; + queue_temp->sg_pool = NULL; + continue; + } + + /* + * The dma pool for queue command buffer. + */ + queue_temp->comp_pool = dma_pool_create("comp_pool", + &pdev->dev, + FSL_QDMA_BASE_BUFFER_SIZE, + 16, 0); + if (!queue_temp->comp_pool) { + dma_free_coherent(&pdev->dev, + sizeof(struct fsl_qdma_ccdf) * + qdma_queue_sizes[i], + queue_temp->cq, + queue_temp->bus_addr); + return NULL; + } + /* + * The dma pool for queue command buffer. + */ + queue_temp->sg_pool = dma_pool_create("sg_pool", + &pdev->dev, + FSL_QDMA_EXPECT_SG_ENTRY_NUM * 16, + 64, 0); + if (!queue_temp->sg_pool) { + dma_free_coherent(&pdev->dev, + sizeof(struct fsl_qdma_ccdf) * + qdma_queue_sizes[i], + queue_temp->cq, + queue_temp->bus_addr); + dma_pool_destroy(queue_temp->comp_pool); + return NULL; + } + /* + * List for queue command buffer. + */ + INIT_LIST_HEAD(&queue_temp->comp_used); + INIT_LIST_HEAD(&queue_temp->comp_free); + spin_lock_init(&queue_temp->queue_lock); + } + + return queue_head; +} + +static int fsl_qdma_halt(struct fsl_qdma_engine *fsl_qdma) +{ + void __iomem *ctrl = fsl_qdma->ctrl_base; + void __iomem *block = fsl_qdma->block_base; + int i, count = 5; + u32 reg; + + /* Disable the command queue and wait for idle state. */ + reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DMR); + reg |= FSL_QDMA_DMR_DQD; + qdma_writel(fsl_qdma, reg, ctrl + FSL_QDMA_DMR); + for (i = 0; i < FSL_QDMA_MAX_QUEUE; i++) + qdma_writel(fsl_qdma, 0, block + FSL_QDMA_BCQMR(i)); + + while (1) { + reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DSR); + if (!(reg & FSL_QDMA_DSR_DB)) + break; + if (count-- < 0) + return -EBUSY; + udelay(100); + } + + /* Disable status queue. */ + qdma_writel(fsl_qdma, 0, block + FSL_QDMA_BSQMR); + + /* + * Clear the command queue interrupt detect register for all queues. + */ + qdma_writel(fsl_qdma, 0xffffffff, block + FSL_QDMA_BCQIDR(0)); + + return 0; +} + +static void fsl_qdma_queue_complete(struct fsl_qdma_engine *fsl_qdma, + enum dma_status status) +{ + struct fsl_qdma_queue *fsl_queue = fsl_qdma->queue; + struct fsl_qdma_queue *fsl_status = fsl_qdma->status; + struct fsl_qdma_queue *temp_queue; + struct fsl_qdma_comp *fsl_comp; + struct fsl_qdma_ccdf *status_addr; + void __iomem *block = fsl_qdma->block_base; + u64 bus_addr; + u32 reg, i; + + while (1) { + status_addr = fsl_status->virt_head; + /* + * Sacn all the queues. + * Match which queue completed this transfer. + */ + for (i = 0; i < fsl_qdma->n_queues; i++) { + temp_queue = fsl_queue + i; + if (list_empty(&temp_queue->comp_used)) + continue; + fsl_comp = list_first_entry(&temp_queue->comp_used, + struct fsl_qdma_comp, + list); + bus_addr = status_addr->dd_q_addr_high + & QDMA_CCDF_ADDR_HIGH_MASK; + bus_addr = bus_addr << 32 | status_addr->addr_low; + if (fsl_comp->bus_addr + 16 != (dma_addr_t)bus_addr) + continue; + spin_lock(&temp_queue->queue_lock); + list_del(&fsl_comp->list); + spin_unlock(&temp_queue->queue_lock); + + reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQMR); + reg |= FSL_QDMA_BSQMR_DI; + qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR); + fsl_status->virt_head++; + if (fsl_status->virt_head == fsl_status->cq + + fsl_status->n_cq) + fsl_status->virt_head = fsl_status->cq; + + spin_lock(&fsl_comp->qchan->vchan.lock); + if (status == DMA_COMPLETE) + vchan_cookie_complete(&fsl_comp->vdesc); + fsl_comp->qchan->status = status; + + spin_unlock(&fsl_comp->qchan->vchan.lock); + break; + } + reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQSR); + if (reg & FSL_QDMA_BSQSR_QE) + break; + if (i == fsl_qdma->n_queues) { + /* + * QDMA can't find the corresponding completed queue. + */ + return; + } + } +} + +static irqreturn_t fsl_qdma_error_handler(int irq, void *dev_id) +{ + struct fsl_qdma_engine *fsl_qdma = dev_id; + unsigned int intr; + void __iomem *ctrl = fsl_qdma->ctrl_base; + + intr = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DEDR); + + if (!intr) + return IRQ_NONE; + + fsl_qdma_queue_complete(fsl_qdma, DMA_ERROR); + qdma_writel(fsl_qdma, 0xffffffff, ctrl + FSL_QDMA_DEDR); + return IRQ_HANDLED; +} + +static irqreturn_t fsl_qdma_queue_handler(int irq, void *dev_id) +{ + struct fsl_qdma_engine *fsl_qdma = dev_id; + unsigned int intr, intr_err; + void __iomem *block = fsl_qdma->block_base; + void __iomem *ctrl = fsl_qdma->ctrl_base; + int ret = IRQ_NONE; + + intr = qdma_readl(fsl_qdma, block + FSL_QDMA_BCQIDR(0)); + intr_err = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DEDR); + + if ((intr & FSL_QDMA_CQIDR_SQT) != 0) { + if (intr_err) { + fsl_qdma_queue_complete(fsl_qdma, DMA_ERROR); + qdma_writel(fsl_qdma, 0xffffffff, ctrl + FSL_QDMA_DEDR); + } else + fsl_qdma_queue_complete(fsl_qdma, DMA_COMPLETE); + ret = IRQ_HANDLED; + } + + qdma_writel(fsl_qdma, 0xffffffff, block + FSL_QDMA_BCQIDR(0)); + return ret; +} + +static int +fsl_qdma_irq_init(struct platform_device *pdev, + struct fsl_qdma_engine *fsl_qdma) +{ + int ret; + + fsl_qdma->error_irq = platform_get_irq_byname(pdev, + "qdma-error"); + if (fsl_qdma->error_irq < 0) { + dev_err(&pdev->dev, "Can't get qdma controller irq.\n"); + return fsl_qdma->error_irq; + } + + fsl_qdma->queue_irq = platform_get_irq_byname(pdev, "qdma-queue"); + if (fsl_qdma->queue_irq < 0) { + dev_err(&pdev->dev, "Can't get qdma queue irq.\n"); + return fsl_qdma->queue_irq; + } + + ret = devm_request_irq(&pdev->dev, fsl_qdma->error_irq, + fsl_qdma_error_handler, 0, "qDMA error", fsl_qdma); + if (ret) { + dev_err(&pdev->dev, "Can't register qDMA controller IRQ.\n"); + return ret; + } + ret = devm_request_irq(&pdev->dev, fsl_qdma->queue_irq, + fsl_qdma_queue_handler, 0, "qDMA queue", fsl_qdma); + if (ret) { + dev_err(&pdev->dev, "Can't register qDMA queue IRQ.\n"); + return ret; + } + + return 0; +} + +static int fsl_qdma_reg_init(struct fsl_qdma_engine *fsl_qdma) +{ + struct fsl_qdma_queue *fsl_queue = fsl_qdma->queue; + struct fsl_qdma_queue *temp; + void __iomem *ctrl = fsl_qdma->ctrl_base; + void __iomem *block = fsl_qdma->block_base; + int i, ret; + u32 reg; + + /* Try to halt the qDMA engine first. */ + ret = fsl_qdma_halt(fsl_qdma); + if (ret) { + dev_err(fsl_qdma->dma_dev.dev, "DMA halt failed!"); + return ret; + } + + /* + * Clear the command queue interrupt detect register for all queues. + */ + qdma_writel(fsl_qdma, 0xffffffff, block + FSL_QDMA_BCQIDR(0)); + + for (i = 0; i < fsl_qdma->n_queues; i++) { + temp = fsl_queue + i; + /* + * Initialize Command Queue registers to point to the first + * command descriptor in memory. + * Dequeue Pointer Address Registers + * Enqueue Pointer Address Registers + */ + qdma_writel(fsl_qdma, temp->bus_addr, + block + FSL_QDMA_BCQDPA_SADDR(i)); + qdma_writel(fsl_qdma, temp->bus_addr, + block + FSL_QDMA_BCQEPA_SADDR(i)); + + /* Initialize the queue mode. */ + reg = FSL_QDMA_BCQMR_EN; + reg |= FSL_QDMA_BCQMR_CD_THLD(ilog2(temp->n_cq)-4); + reg |= FSL_QDMA_BCQMR_CQ_SIZE(ilog2(temp->n_cq)-6); + qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BCQMR(i)); + } + + /* + * Initialize status queue registers to point to the first + * command descriptor in memory. + * Dequeue Pointer Address Registers + * Enqueue Pointer Address Registers + */ + qdma_writel(fsl_qdma, fsl_qdma->status->bus_addr, + block + FSL_QDMA_SQEPAR); + qdma_writel(fsl_qdma, fsl_qdma->status->bus_addr, + block + FSL_QDMA_SQDPAR); + /* Initialize status queue interrupt. */ + qdma_writel(fsl_qdma, FSL_QDMA_BCQIER_CQTIE, + block + FSL_QDMA_BCQIER(0)); + qdma_writel(fsl_qdma, FSL_QDMA_BSQICR_ICEN | FSL_QDMA_BSQICR_ICST(1), + block + FSL_QDMA_BSQICR); + qdma_writel(fsl_qdma, FSL_QDMA_CQIER_MEIE | FSL_QDMA_CQIER_TEIE, + block + FSL_QDMA_CQIER); + /* Initialize controller interrupt register. */ + qdma_writel(fsl_qdma, 0xffffffff, ctrl + FSL_QDMA_DEDR); + qdma_writel(fsl_qdma, 0xffffffff, ctrl + FSL_QDMA_DEIER); + + /* Initialize the status queue mode. */ + reg = FSL_QDMA_BSQMR_EN; + reg |= FSL_QDMA_BSQMR_CQ_SIZE(ilog2(fsl_qdma->status->n_cq)-6); + qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR); + + reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DMR); + reg &= ~FSL_QDMA_DMR_DQD; + qdma_writel(fsl_qdma, reg, ctrl + FSL_QDMA_DMR); + + return 0; +} + +static struct dma_async_tx_descriptor *fsl_qdma_prep_dma_sg( + struct dma_chan *chan, + struct scatterlist *dst_sg, unsigned int dst_nents, + struct scatterlist *src_sg, unsigned int src_nents, + unsigned long flags) +{ + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + struct fsl_qdma_comp *fsl_comp; + + fsl_comp = fsl_qdma_request_enqueue_desc(fsl_chan, + dst_nents, + src_nents); + fsl_qdma_comp_fill_sg(fsl_comp, dst_sg, dst_nents, src_sg, src_nents); + + return vchan_tx_prep(&fsl_chan->vchan, &fsl_comp->vdesc, flags); +} + +static struct dma_async_tx_descriptor * +fsl_qdma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, + dma_addr_t src, size_t len, unsigned long flags) +{ + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + struct fsl_qdma_comp *fsl_comp; + + fsl_comp = fsl_qdma_request_enqueue_desc(fsl_chan, 0, 0); + fsl_qdma_comp_fill_memcpy(fsl_comp, dst, src, len); + + return vchan_tx_prep(&fsl_chan->vchan, &fsl_comp->vdesc, flags); +} + +static void fsl_qdma_enqueue_desc(struct fsl_qdma_chan *fsl_chan) +{ + void __iomem *block = fsl_chan->qdma->block_base; + struct fsl_qdma_queue *fsl_queue = fsl_chan->queue; + struct fsl_qdma_comp *fsl_comp; + struct virt_dma_desc *vdesc; + u32 reg; + + reg = qdma_readl(fsl_chan->qdma, block + FSL_QDMA_BCQSR(fsl_queue->id)); + if (reg & FSL_QDMA_BCQSR_QF) + return; + vdesc = vchan_next_desc(&fsl_chan->vchan); + if (!vdesc) + return; + list_del(&vdesc->node); + fsl_comp = to_fsl_qdma_comp(vdesc); + + memcpy(fsl_queue->virt_head++, fsl_comp->virt_addr, 16); + if (fsl_queue->virt_head == fsl_queue->cq + fsl_queue->n_cq) + fsl_queue->virt_head = fsl_queue->cq; + + list_add_tail(&fsl_comp->list, &fsl_queue->comp_used); + reg = qdma_readl(fsl_chan->qdma, block + FSL_QDMA_BCQMR(fsl_queue->id)); + reg |= FSL_QDMA_BCQMR_EI; + qdma_writel(fsl_chan->qdma, reg, block + FSL_QDMA_BCQMR(fsl_queue->id)); + fsl_chan->status = DMA_IN_PROGRESS; +} + +static enum dma_status fsl_qdma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate) +{ + return dma_cookie_status(chan, cookie, txstate); +} + +static void fsl_qdma_free_desc(struct virt_dma_desc *vdesc) +{ + struct fsl_qdma_comp *fsl_comp; + struct fsl_qdma_queue *fsl_queue; + struct fsl_qdma_sg *sg_block; + unsigned long flags; + unsigned int i; + + fsl_comp = to_fsl_qdma_comp(vdesc); + fsl_queue = fsl_comp->qchan->queue; + + if (fsl_comp->sg_block) { + for (i = 0; i < fsl_comp->sg_block_src + + fsl_comp->sg_block_dst; i++) { + sg_block = fsl_comp->sg_block + i; + dma_pool_free(fsl_queue->sg_pool, + sg_block->virt_addr, + sg_block->bus_addr); + } + kfree(fsl_comp->sg_block); + } + + spin_lock_irqsave(&fsl_queue->queue_lock, flags); + list_add_tail(&fsl_comp->list, &fsl_queue->comp_free); + spin_unlock_irqrestore(&fsl_queue->queue_lock, flags); +} + +static void fsl_qdma_issue_pending(struct dma_chan *chan) +{ + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); + struct fsl_qdma_queue *fsl_queue = fsl_chan->queue; + unsigned long flags; + + spin_lock_irqsave(&fsl_queue->queue_lock, flags); + spin_lock(&fsl_chan->vchan.lock); + if (vchan_issue_pending(&fsl_chan->vchan)) + fsl_qdma_enqueue_desc(fsl_chan); + spin_unlock(&fsl_chan->vchan.lock); + spin_unlock_irqrestore(&fsl_queue->queue_lock, flags); +} + +static int fsl_qdma_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct fsl_qdma_engine *fsl_qdma; + struct fsl_qdma_chan *fsl_chan; + struct resource *res; + int len, ret, i; + + if (channels > FSL_QDMA_MAX_BLOCK * FSL_QDMA_MAX_QUEUE) { + dev_warn(&pdev->dev, + "The max number of the channels is: %d\n", + FSL_QDMA_MAX_BLOCK * FSL_QDMA_MAX_QUEUE); + channels = FSL_QDMA_MAX_BLOCK * FSL_QDMA_MAX_QUEUE; + } + + len = sizeof(*fsl_qdma) + sizeof(*fsl_chan) * channels; + fsl_qdma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!fsl_qdma) + return -ENOMEM; + + fsl_qdma->queue = fsl_qdma_alloc_queue_resources(pdev, QDMA_QUEUE); + if (!fsl_qdma->queue) + return -ENOMEM; + + fsl_qdma->status = fsl_qdma_alloc_queue_resources(pdev, QDMA_STATUS); + if (!fsl_qdma->status) + return -ENOMEM; + + fsl_qdma->n_chans = channels; + fsl_qdma->n_queues = queue_num; + mutex_init(&fsl_qdma->fsl_qdma_mutex); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fsl_qdma->ctrl_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fsl_qdma->ctrl_base)) + return PTR_ERR(fsl_qdma->ctrl_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + fsl_qdma->block_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fsl_qdma->block_base)) + return PTR_ERR(fsl_qdma->block_base); + + ret = fsl_qdma_irq_init(pdev, fsl_qdma); + if (ret) + return ret; + + fsl_qdma->big_endian = of_property_read_bool(np, "big-endian"); + INIT_LIST_HEAD(&fsl_qdma->dma_dev.channels); + for (i = 0; i < fsl_qdma->n_chans; i++) { + struct fsl_qdma_chan *fsl_chan = &fsl_qdma->chans[i]; + + fsl_chan->qdma = fsl_qdma; + fsl_chan->queue = fsl_qdma->queue; + fsl_chan->vchan.desc_free = fsl_qdma_free_desc; + INIT_LIST_HEAD(&fsl_chan->qcomp); + vchan_init(&fsl_chan->vchan, &fsl_qdma->dma_dev); + } + + dma_cap_set(DMA_MEMCPY, fsl_qdma->dma_dev.cap_mask); + dma_cap_set(DMA_SG, fsl_qdma->dma_dev.cap_mask); + + fsl_qdma->dma_dev.dev = &pdev->dev; + fsl_qdma->dma_dev.device_free_chan_resources + = fsl_qdma_free_chan_resources; + fsl_qdma->dma_dev.device_tx_status = fsl_qdma_tx_status; + fsl_qdma->dma_dev.device_prep_dma_memcpy = fsl_qdma_prep_memcpy; + fsl_qdma->dma_dev.device_prep_dma_sg = fsl_qdma_prep_dma_sg; + fsl_qdma->dma_dev.device_issue_pending = fsl_qdma_issue_pending; + + dma_set_mask(&pdev->dev, DMA_BIT_MASK(40)); + + platform_set_drvdata(pdev, fsl_qdma); + + ret = dma_async_device_register(&fsl_qdma->dma_dev); + if (ret) { + dev_err(&pdev->dev, "Can't register QorIQ qDMA engine.\n"); + return ret; + } + + ret = fsl_qdma_reg_init(fsl_qdma); + if (ret) { + dev_err(&pdev->dev, "Can't Initialize the qDMA engine.\n"); + return ret; + } + + + return 0; +} + +static int fsl_qdma_remove(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct fsl_qdma_engine *fsl_qdma = platform_get_drvdata(pdev); + struct fsl_qdma_queue *queue_temp; + struct fsl_qdma_queue *status = fsl_qdma->status; + struct fsl_qdma_comp *comp_temp, *_comp_temp; + int i; + + of_dma_controller_free(np); + dma_async_device_unregister(&fsl_qdma->dma_dev); + + /* Free descriptor areas */ + for (i = 0; i < fsl_qdma->n_queues; i++) { + queue_temp = fsl_qdma->queue + i; + list_for_each_entry_safe(comp_temp, _comp_temp, + &queue_temp->comp_used, list) { + dma_pool_free(queue_temp->comp_pool, + comp_temp->virt_addr, + comp_temp->bus_addr); + list_del(&comp_temp->list); + kfree(comp_temp); + } + list_for_each_entry_safe(comp_temp, _comp_temp, + &queue_temp->comp_free, list) { + dma_pool_free(queue_temp->comp_pool, + comp_temp->virt_addr, + comp_temp->bus_addr); + list_del(&comp_temp->list); + kfree(comp_temp); + } + dma_free_coherent(&pdev->dev, sizeof(struct fsl_qdma_ccdf) * + queue_temp->n_cq, queue_temp->cq, + queue_temp->bus_addr); + dma_pool_destroy(queue_temp->comp_pool); + } + + dma_free_coherent(&pdev->dev, sizeof(struct fsl_qdma_ccdf) * + status->n_cq, status->cq, status->bus_addr); + return 0; +} + +static const struct of_device_id fsl_qdma_dt_ids[] = { + { .compatible = "fsl,ls1021a-qdma", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_qdma_dt_ids); + +static struct platform_driver fsl_qdma_driver = { + .driver = { + .name = "fsl-qdma", + .owner = THIS_MODULE, + .of_match_table = fsl_qdma_dt_ids, + }, + .probe = fsl_qdma_probe, + .remove = fsl_qdma_remove, +}; + +static int __init fsl_qdma_init(void) +{ + return platform_driver_register(&fsl_qdma_driver); +} +subsys_initcall(fsl_qdma_init); + +static void __exit fsl_qdma_exit(void) +{ + platform_driver_unregister(&fsl_qdma_driver); +} +module_exit(fsl_qdma_exit); + +MODULE_DESCRIPTION("QorIQ qDMA engine driver"); +MODULE_AUTHOR("Yuan Yao <yao.yuan@nxp.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/qoriq-qdma.h b/drivers/dma/qoriq-qdma.h new file mode 100644 index 0000000..0b827db --- /dev/null +++ b/drivers/dma/qoriq-qdma.h @@ -0,0 +1,272 @@ +/* + * drivers/dma/qoriq-qdma.h + * + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * + * Driver for the Freescale qDMA engine with software command queue mode. + * Channel virtualization is supported through enqueuing of DMA jobs to, + * or dequeuing DMA jobs from, different work queues. + * This module can be found on Freescale LS SoCs. + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __DMA_QORIQ_QDMA_H__ +#define __DMA_QORIQ_QDMA_H__ + +#include "virt-dma.h" + +#define FSL_QDMA_DMR 0x0 +#define FSL_QDMA_DSR 0x4 +#define FSL_QDMA_DEIER 0x1e00 +#define FSL_QDMA_DEDR 0x1e04 +#define FSL_QDMA_DECFDW0R 0x1e10 +#define FSL_QDMA_DECFDW1R 0x1e14 +#define FSL_QDMA_DECFDW2R 0x1e18 +#define FSL_QDMA_DECFDW3R 0x1e1c +#define FSL_QDMA_DECFQIDR 0x1e30 +#define FSL_QDMA_DECBR 0x1e34 + +#define FSL_QDMA_BCQMR(x) (0xc0 + 0x100 * (x)) +#define FSL_QDMA_BCQSR(x) (0xc4 + 0x100 * (x)) +#define FSL_QDMA_BCQEDPA_SADDR(x) (0xc8 + 0x100 * (x)) +#define FSL_QDMA_BCQDPA_SADDR(x) (0xcc + 0x100 * (x)) +#define FSL_QDMA_BCQEEPA_SADDR(x) (0xd0 + 0x100 * (x)) +#define FSL_QDMA_BCQEPA_SADDR(x) (0xd4 + 0x100 * (x)) +#define FSL_QDMA_BCQIER(x) (0xe0 + 0x100 * (x)) +#define FSL_QDMA_BCQIDR(x) (0xe4 + 0x100 * (x)) + +#define FSL_QDMA_SQDPAR 0x80c +#define FSL_QDMA_SQEPAR 0x814 +#define FSL_QDMA_BSQMR 0x800 +#define FSL_QDMA_BSQSR 0x804 +#define FSL_QDMA_BSQICR 0x828 +#define FSL_QDMA_CQMR 0xa00 +#define FSL_QDMA_CQDSCR1 0xa08 +#define FSL_QDMA_CQDSCR2 0xa0c +#define FSL_QDMA_CQIER 0xa10 +#define FSL_QDMA_CQEDR 0xa14 + +#define FSL_QDMA_SQICR_ICEN + +#define FSL_QDMA_CQIDR_CQT 0xff000000 +#define FSL_QDMA_CQIDR_SQPE 0x800000 +#define FSL_QDMA_CQIDR_SQT 0x8000 + +#define FSL_QDMA_BCQIER_CQTIE 0x8000 +#define FSL_QDMA_BCQIER_CQPEIE 0x800000 +#define FSL_QDMA_BSQICR_ICEN 0x80000000 +#define FSL_QDMA_BSQICR_ICST(x) ((x) << 16) +#define FSL_QDMA_CQIER_MEIE 0x80000000 +#define FSL_QDMA_CQIER_TEIE 0x1 + +#define FSL_QDMA_BCQMR_EN 0x80000000 +#define FSL_QDMA_BCQMR_EI 0x40000000 +#define FSL_QDMA_BCQMR_CD_THLD(x) ((x) << 20) +#define FSL_QDMA_BCQMR_CQ_SIZE(x) ((x) << 16) + +#define FSL_QDMA_BCQSR_QF 0x10000 + +#define FSL_QDMA_BSQMR_EN 0x80000000 +#define FSL_QDMA_BSQMR_DI 0x40000000 +#define FSL_QDMA_BSQMR_CQ_SIZE(x) ((x) << 16) + +#define FSL_QDMA_BSQSR_QE 0x20000 + +#define FSL_QDMA_DMR_DQD 0x40000000 +#define FSL_QDMA_DSR_DB 0x80000000 + +#define FSL_QDMA_CMD_RWTTYPE 0x4 + +#define FSL_QDMA_CMD_RWTTYPE_OFFSET 28 +#define FSL_QDMA_CMD_NS_OFFSET 27 +#define FSL_QDMA_CMD_DQOS_OFFSET 24 +#define FSL_QDMA_CMD_WTHROTL_OFFSET 20 +#define FSL_QDMA_CMD_DSEN_OFFSET 19 +#define FSL_QDMA_CMD_LWC_OFFSET 16 + +#define FSL_QDMA_E_SG_TABLE 1 +#define FSL_QDMA_E_DATA_BUFFER 0 + +#define FSL_QDMA_MAX_BLOCK 4 +#define FSL_QDMA_MAX_QUEUE 8 +#define FSL_QDMA_BASE_BUFFER_SIZE 96 +#define FSL_QDMA_EXPECT_SG_ENTRY_NUM 16 +#define FSL_QDMA_CIRCULAR_SIZE_MIN 64 +#define FSL_QDMA_CIRCULAR_SIZE_MAX 16384 + +/* + * Descriptor bit shifts and masks. + */ + +#define QDMA_CSGF_OFFSET_SHIFT 0 +#define QDMA_CSGF_OFFSET_MASK 0x1fff +#define QDMA_CSGF_LENGTH_SHIFT 0 +#define QDMA_CSGF_LENGTH_MASK 0x3 +#define QDMA_CSGF_F (1UL << 30) +#define QDMA_CSGF_E (1UL << 31) +#define QDMA_CSGF_ADDR_LOW_MASK 0xffffffff +#define QDMA_CSGF_ADDR_GIHG_SHIFT 0 +#define QDMA_CSGF_ADDR_HIGH_MASK 0xff + +#define QDMA_CCDF_STATUS_SHIFT 0 +#define QDMA_CCDF_STATUS_MASK 0xff +#define QDMA_CCDF_SER (1UL << 30) +#define QDMA_CCDF_OFFSET_SHIFT 20 +#define QDMA_CCDF_OFFSET_MASK 0x1ff +#define QDMA_CCDF_FORMAT_SHIFT 29 +#define QDMA_CCDF_FORMAT_MASK 0x3 +#define QDMA_CCDF_ADDR_LOW_MASK 0xffffffff +#define QDMA_CCDF_ADDR_GIHG_SHIFT 0 +#define QDMA_CCDF_ADDR_HIGH_MASK 0xff +#define QDMA_CCDF_QUEUE_SHIFT 24 +#define QDMA_CCDF_QUEUE_MASK 0x3 +#define QDMA_CCDF_DD_SHIFT 30 +#define QDMA_CCDF_DD_MASK 0x2 + +#define QDMA_SDF_SSD_SHIFT 0 +#define QDMA_SDF_SSD_MASK 0xfff +#define QDMA_SDF_SSS_SHIFT 12 +#define QDMA_SDF_SSS_MASK 0xfff +#define QDMA_SDF_CMD_MASK 0xffffffff + +#define QDMA_DDF_DSD_SHIFT 0 +#define QDMA_DDF_DSD_MASK 0xfff +#define QDMA_DDF_DSS_SHIFT 12 +#define QDMA_DDF_DSS_MASK 0xfff +#define QDMA_DDF_CMD_MASK 0xffffffff + +/* + * enum qdma_queue_type - QDMA queue type + * @QDMA_QUEUE: work command queue + * @QDMA_STATUS: work status queue + */ +enum qdma_queue_type { + QDMA_QUEUE, + QDMA_STATUS, +}; + +struct fsl_qdma_ccdf { + u32 ser_status; + u32 format_offset; + u32 addr_low; + u32 dd_q_addr_high; +}; + +struct fsl_qdma_csgf { + u32 offset; + u32 e_f_length; + u32 addr_low; + u32 addr_high; +}; + +struct fsl_qdma_sdf { + u32 rev1; + u32 sss_ssd; + u32 rev2; + u32 cmd; +}; + +struct fsl_qdma_ddf { + u32 rev1; + u32 dss_dsd; + u32 rev2; + u32 cmd; +}; + +struct fsl_qdma_chan { + struct virt_dma_chan vchan; + struct virt_dma_desc vdesc; + enum dma_status status; + u32 slave_id; + struct fsl_qdma_engine *qdma; + struct fsl_qdma_queue *queue; + struct list_head qcomp; +}; + +struct fsl_qdma_queue { + struct fsl_qdma_ccdf *virt_head; + struct fsl_qdma_ccdf *virt_tail; + struct list_head comp_used; + struct list_head comp_free; + struct dma_pool *comp_pool; + struct dma_pool *sg_pool; + spinlock_t queue_lock; + dma_addr_t bus_addr; + u32 n_cq; + u32 id; + struct fsl_qdma_ccdf *cq; +}; + +struct fsl_qdma_sg { + dma_addr_t bus_addr; + void *virt_addr; +}; + +struct fsl_qdma_comp { + dma_addr_t bus_addr; + void *virt_addr; + struct fsl_qdma_chan *qchan; + struct fsl_qdma_sg *sg_block; + struct virt_dma_desc vdesc; + struct list_head list; + u32 sg_block_src; + u32 sg_block_dst; +}; + +struct fsl_qdma_engine { + struct dma_device dma_dev; + void __iomem *ctrl_base; + void __iomem *block_base; + u32 n_chans; + u32 n_queues; + struct mutex fsl_qdma_mutex; + int error_irq; + int queue_irq; + bool big_endian; + struct fsl_qdma_queue *queue; + struct fsl_qdma_queue *status; + struct fsl_qdma_chan chans[]; + +}; + +struct fsl_qdma_frame { + struct fsl_qdma_ccdf ccdf; + struct fsl_qdma_csgf csgf_desc; + struct fsl_qdma_csgf csgf_src; + struct fsl_qdma_csgf csgf_dest; + struct fsl_qdma_sdf sdf; + struct fsl_qdma_ddf ddf; +}; + +static u32 qdma_readl(struct fsl_qdma_engine *qdma, u32 __iomem *addr) +{ + if (qdma->big_endian) + return ioread32be(addr); + else + return ioread32(addr); +} + +static void qdma_writel(struct fsl_qdma_engine *qdma, u32 val, + u32 __iomem *addr) +{ + if (qdma->big_endian) + iowrite32be(val, addr); + else + iowrite32(val, addr); +} + +static struct fsl_qdma_chan *to_fsl_qdma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct fsl_qdma_chan, vchan.chan); +} + +static struct fsl_qdma_comp *to_fsl_qdma_comp(struct virt_dma_desc *vd) +{ + return container_of(vd, struct fsl_qdma_comp, vdesc); +} + +#endif /* __DMA_QORIQ_QDMA_H__ */ -- 2.1.0.27.g96db324 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 1/5] dma: Add QorIQ qDMA engine driver support 2016-08-18 6:38 ` [PATCH v1 1/5] " Yuan Yao @ 2016-08-18 9:16 ` Russell King - ARM Linux 2016-08-24 3:39 ` Yao Yuan 2016-08-23 12:18 ` kbuild test robot 2016-08-23 12:18 ` [PATCH] dma: fix platform_no_drv_owner.cocci warnings kbuild test robot 2 siblings, 1 reply; 14+ messages in thread From: Russell King - ARM Linux @ 2016-08-18 9:16 UTC (permalink / raw) To: Yuan Yao Cc: vinod.koul, robh+dt, dan.j.williams, mark.rutland, shawnguo, leoyang.li, dmaengine, linux-kernel, linux-arm-kernel, Yuan Yao On Thu, Aug 18, 2016 at 02:38:44PM +0800, Yuan Yao wrote: > + spin_lock(&fsl_comp->qchan->vchan.lock); > + if (status == DMA_COMPLETE) > + vchan_cookie_complete(&fsl_comp->vdesc); > + fsl_comp->qchan->status = status; This is buggy - if the DMA has finished processing it, even if it finished in error, it must _complete_ the transaction. Completion is not the same as being successful - it means that the DMA is no longer processing the cookie. The issue here is that when the _following_ transaction completes successfully, _this_ transaction will effectively be marked as complete due to the way the cookie system works. So... to get this straight - "completion" means "I have finished processing this transaction". It does not mean "I successfully processed this transaction without any errors." -- RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up according to speedtest.net. ^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [PATCH v1 1/5] dma: Add QorIQ qDMA engine driver support 2016-08-18 9:16 ` Russell King - ARM Linux @ 2016-08-24 3:39 ` Yao Yuan 0 siblings, 0 replies; 14+ messages in thread From: Yao Yuan @ 2016-08-24 3:39 UTC (permalink / raw) To: Russell King - ARM Linux, Yuan Yao Cc: vinod.koul, robh+dt, dan.j.williams, mark.rutland, shawnguo, Yang-Leo Li, dmaengine, linux-kernel, linux-arm-kernel On Thu, Aug 18, 2016 at 05:16 PM +0800, Russell King wrote: > On Thu, Aug 18, 2016 at 02:38:44PM +0800, Yuan Yao wrote: > > + spin_lock(&fsl_comp->qchan->vchan.lock); > > + if (status == DMA_COMPLETE) > > + vchan_cookie_complete(&fsl_comp->vdesc); > > + fsl_comp->qchan->status = status; > > This is buggy - if the DMA has finished processing it, even if it finished in error, it > must _complete_ the transaction. Completion is not the same as being > successful - it means that the DMA is no longer processing the cookie. > > The issue here is that when the _following_ transaction completes successfully, > _this_ transaction will effectively be marked as complete due to the way the > cookie system works. > > So... to get this straight - "completion" means "I have finished processing this > transaction". It does not mean "I successfully processed this transaction > without any errors." > Thanks for your review. So you mean that I should call vchan_cookie_complete no matter whether the error issue in QDMA? I have some random DMA error test case, it seems work will. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 1/5] dma: Add QorIQ qDMA engine driver support 2016-08-18 6:38 ` [PATCH v1 1/5] " Yuan Yao 2016-08-18 9:16 ` Russell King - ARM Linux @ 2016-08-23 12:18 ` kbuild test robot 2016-08-23 12:18 ` [PATCH] dma: fix platform_no_drv_owner.cocci warnings kbuild test robot 2 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2016-08-23 12:18 UTC (permalink / raw) To: Yuan Yao Cc: kbuild-all, vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo, leoyang.li, dmaengine, linux-kernel, linux-arm-kernel, Yuan Yao Hi Yuan, [auto build test WARNING on linus/master] [also build test WARNING on v4.8-rc3 next-20160823] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] [Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on] [Check https://git-scm.com/docs/git-format-patch for more information] url: https://github.com/0day-ci/linux/commits/Yuan-Yao/dma-Add-QorIQ-qDMA-engine-driver-support/20160818-152520 coccinelle warnings: (new ones prefixed by >>) >> drivers/dma/qoriq-qdma.c:879:3-8: No need to set .owner here. The core will do it. Please review and possibly fold the followup patch. --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH] dma: fix platform_no_drv_owner.cocci warnings 2016-08-18 6:38 ` [PATCH v1 1/5] " Yuan Yao 2016-08-18 9:16 ` Russell King - ARM Linux 2016-08-23 12:18 ` kbuild test robot @ 2016-08-23 12:18 ` kbuild test robot 2 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2016-08-23 12:18 UTC (permalink / raw) To: Yuan Yao Cc: kbuild-all, vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo, leoyang.li, dmaengine, linux-kernel, linux-arm-kernel, Yuan Yao drivers/dma/qoriq-qdma.c:879:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Yuan Yao <yao.yuan@nxp.com> Signed-off-by: Fengguang Wu <fengguang.wu@intel.com> --- qoriq-qdma.c | 1 - 1 file changed, 1 deletion(-) --- a/drivers/dma/qoriq-qdma.c +++ b/drivers/dma/qoriq-qdma.c @@ -876,7 +876,6 @@ MODULE_DEVICE_TABLE(of, fsl_qdma_dt_ids) static struct platform_driver fsl_qdma_driver = { .driver = { .name = "fsl-qdma", - .owner = THIS_MODULE, .of_match_table = fsl_qdma_dt_ids, }, .probe = fsl_qdma_probe, ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v1 2/5] dma: Add device tree binding for QorIQ qDMA driver 2016-08-18 6:38 [PATCH v1 0/5] dma: Add QorIQ qDMA engine driver support Yuan Yao 2016-08-18 6:38 ` [PATCH v1 1/5] " Yuan Yao @ 2016-08-18 6:38 ` Yuan Yao 2016-08-18 6:38 ` [PATCH v1 3/5] MAINTAINERS: add maintainer entry for QorIQ QDMA driver Yuan Yao ` (2 subsequent siblings) 4 siblings, 0 replies; 14+ messages in thread From: Yuan Yao @ 2016-08-18 6:38 UTC (permalink / raw) To: vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo Cc: leoyang.li, dmaengine, linux-kernel, linux-arm-kernel, Yuan Yao From: Yuan Yao <yao.yuan@nxp.com> Adding devicetree binding for QorIQ queue direct memory access(QDMA). This module can be found on QorIQ LS1021A and LS1043A SoCs. Signed-off-by: Yuan Yao <yao.yuan@nxp.com> --- .../devicetree/bindings/dma/qoriq-qdma.txt | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/qoriq-qdma.txt diff --git a/Documentation/devicetree/bindings/dma/qoriq-qdma.txt b/Documentation/devicetree/bindings/dma/qoriq-qdma.txt new file mode 100644 index 0000000..dfa286e --- /dev/null +++ b/Documentation/devicetree/bindings/dma/qoriq-qdma.txt @@ -0,0 +1,38 @@ +* QorIQ queue Direct Memory Access Controller(qDMA) Controller + + The QorIQ qDMA controller transfers blocks of data between one source and one or more +destinations. The blocks of data transferred can be represented in memory as contiguous +or non-contiguous using scatter/gather table(s). Channel virtualization is supported +through enqueuing of DMA jobs to, or dequeuing DMA jobs from, different work +queues. + +* qDMA Controller +Required properties: +- compatible : + - "fsl,ls1021a-qdma", + Or "fsl,ls1043a-qdma" followed by "fsl,ls1021a-qdma", +- reg : Specifies base physical address(s) and size of the qDMA registers. + The region is qDMA control register's address and size. +- interrupts : A list of interrupt-specifiers, one for each entry in + interrupt-names. +- interrupt-names : Should contain: + "qdma-error" - the error interrupt + "qdma-queue" - the queue interrupt + +Optional properties: +- big-endian: If present registers and hardware scatter/gather descriptors + of the qDMA are implemented in big endian mode, otherwise in little + mode. + + +Examples: + + qdma: qdma@8390000 { + compatible = "fsl,ls1021a-qdma"; + reg = <0x0 0x8398000 0x0 0x2000 /* Controller registers */ + 0x0 0x839a000 0x0 0x2000>; /* Block registers */ + interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "qdma-error", "qdma-queue"; + big-endian; + }; -- 2.1.0.27.g96db324 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v1 3/5] MAINTAINERS: add maintainer entry for QorIQ QDMA driver 2016-08-18 6:38 [PATCH v1 0/5] dma: Add QorIQ qDMA engine driver support Yuan Yao 2016-08-18 6:38 ` [PATCH v1 1/5] " Yuan Yao 2016-08-18 6:38 ` [PATCH v1 2/5] dma: Add device tree binding for QorIQ qDMA driver Yuan Yao @ 2016-08-18 6:38 ` Yuan Yao 2016-08-18 6:38 ` [PATCH v1 4/5] ARM: dts: ls1043a: add qDMA node Yuan Yao 2016-08-18 6:38 ` [PATCH v1 5/5] ARM: dts: ls1021a: " Yuan Yao 4 siblings, 0 replies; 14+ messages in thread From: Yuan Yao @ 2016-08-18 6:38 UTC (permalink / raw) To: vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo Cc: leoyang.li, dmaengine, linux-kernel, linux-arm-kernel, Yuan Yao From: Yuan Yao <yao.yuan@nxp.com> Add a maintainer entry for QorIQ QDMA driver and add myself as a maintainer. Signed-off-by: Yuan Yao <yao.yuan@nxp.com> --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0a309db..278d2f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4934,6 +4934,13 @@ L: linuxppc-dev@lists.ozlabs.org S: Maintained F: drivers/dma/fsldma.* +QorIQ QDMA DRIVER +M: Yuan Yao <yao.yuan@nxp.com> +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/dma/qoriq-qdma.txt +F: drivers/dma/qoriq-qdma.* + FREESCALE GPMI NAND DRIVER M: Han Xu <han.xu@nxp.com> L: linux-mtd@lists.infradead.org -- 2.1.0.27.g96db324 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v1 4/5] ARM: dts: ls1043a: add qDMA node 2016-08-18 6:38 [PATCH v1 0/5] dma: Add QorIQ qDMA engine driver support Yuan Yao ` (2 preceding siblings ...) 2016-08-18 6:38 ` [PATCH v1 3/5] MAINTAINERS: add maintainer entry for QorIQ QDMA driver Yuan Yao @ 2016-08-18 6:38 ` Yuan Yao 2016-08-29 7:29 ` Alexander Stein 2016-08-29 7:34 ` Alexander Stein 2016-08-18 6:38 ` [PATCH v1 5/5] ARM: dts: ls1021a: " Yuan Yao 4 siblings, 2 replies; 14+ messages in thread From: Yuan Yao @ 2016-08-18 6:38 UTC (permalink / raw) To: vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo Cc: leoyang.li, dmaengine, linux-kernel, linux-arm-kernel, Yuan Yao From: Yuan Yao <yao.yuan@nxp.com> Add the QDMA node for ls1043a platform to support QDMA driver. Signed-off-by: Yuan Yao <yao.yuan@nxp.com> --- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index e8e4c3e..e463074 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -467,6 +467,16 @@ <&clockgen 4 0>; }; + qdma: qdma@8390000 { + compatible = "fsl,ls1021a-qdma", "fsl,ls1043a-qdma"; + reg = <0x0 0x838f000 0x0 0x11000 /* Controller regs */ + 0x0 0x83a0000 0x0 0x40000>; /* Block regs */ + interrupts = <0 153 0x4>, + <0 39 0x4>; + interrupt-names = "qdma-error", "qdma-queue"; + big-endian; + }; + usb0: usb3@2f00000 { compatible = "snps,dwc3"; reg = <0x0 0x2f00000 0x0 0x10000>; -- 2.1.0.27.g96db324 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 4/5] ARM: dts: ls1043a: add qDMA node 2016-08-18 6:38 ` [PATCH v1 4/5] ARM: dts: ls1043a: add qDMA node Yuan Yao @ 2016-08-29 7:29 ` Alexander Stein 2016-08-29 7:34 ` Alexander Stein 1 sibling, 0 replies; 14+ messages in thread From: Alexander Stein @ 2016-08-29 7:29 UTC (permalink / raw) To: linux-kernel Cc: Yuan Yao, vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo, leoyang.li, dmaengine, linux-arm-kernel, Yuan Yao On Thursday 18 August 2016 14:38:47, Yuan Yao wrote: > From: Yuan Yao <yao.yuan@nxp.com> > > Add the QDMA node for ls1043a platform to > support QDMA driver. > > Signed-off-by: Yuan Yao <yao.yuan@nxp.com> > --- > arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi > b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index e8e4c3e..e463074 > 100644 > --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi > +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi > @@ -467,6 +467,16 @@ > <&clockgen 4 0>; > }; > > + qdma: qdma@8390000 { > + compatible = "fsl,ls1021a-qdma", "fsl,ls1043a-qdma"; This doesn't match the order of your binding in Patch 2/5: > +- compatible : > + - "fsl,ls1021a-qdma", > + Or "fsl,ls1043a-qdma" followed by "fsl,ls1021a-qdma", It should be the other way around. Best regards, Alexander ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v1 4/5] ARM: dts: ls1043a: add qDMA node 2016-08-18 6:38 ` [PATCH v1 4/5] ARM: dts: ls1043a: add qDMA node Yuan Yao 2016-08-29 7:29 ` Alexander Stein @ 2016-08-29 7:34 ` Alexander Stein 2016-08-31 4:17 ` Yao Yuan 1 sibling, 1 reply; 14+ messages in thread From: Alexander Stein @ 2016-08-29 7:34 UTC (permalink / raw) To: linux-kernel Cc: Yuan Yao, vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo, leoyang.li, dmaengine, linux-arm-kernel, Yuan Yao On Thursday 18 August 2016 14:38:47, Yuan Yao wrote: > From: Yuan Yao <yao.yuan@nxp.com> > > Add the QDMA node for ls1043a platform to > support QDMA driver. > > Signed-off-by: Yuan Yao <yao.yuan@nxp.com> > --- > arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi > b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index e8e4c3e..e463074 > 100644 > --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi > +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi > @@ -467,6 +467,16 @@ > <&clockgen 4 0>; > }; > > + qdma: qdma@8390000 { > + compatible = "fsl,ls1021a-qdma", "fsl,ls1043a-qdma"; This doesn't match the order of your binding in Patch 2/5: > +- compatible : > + - "fsl,ls1021a-qdma", > + Or "fsl,ls1043a-qdma" followed by "fsl,ls1021a-qdma", It should be the other way around. Best regards, Alexander ^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: [PATCH v1 4/5] ARM: dts: ls1043a: add qDMA node 2016-08-29 7:34 ` Alexander Stein @ 2016-08-31 4:17 ` Yao Yuan 0 siblings, 0 replies; 14+ messages in thread From: Yao Yuan @ 2016-08-31 4:17 UTC (permalink / raw) To: Alexander Stein, linux-kernel Cc: Yuan Yao, vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo, Yang-Leo Li, dmaengine, linux-arm-kernel On Mon 29 August 2016 03:34:47, : Alexander Stein wrote: > On Thursday 18 August 2016 14:38:47, Yuan Yao wrote: > > From: Yuan Yao <yao.yuan@nxp.com> > > > > Add the QDMA node for ls1043a platform to support QDMA driver. > > > > Signed-off-by: Yuan Yao <yao.yuan@nxp.com> > > --- > > arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 10 ++++++++++ > > 1 file changed, 10 insertions(+) > > > > diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi > > b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index > > e8e4c3e..e463074 > > 100644 > > --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi > > +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi > > @@ -467,6 +467,16 @@ > > <&clockgen 4 0>; > > }; > > > > + qdma: qdma@8390000 { > > + compatible = "fsl,ls1021a-qdma", "fsl,ls1043a-qdma"; > > This doesn't match the order of your binding in Patch 2/5: > > +- compatible : > > + - "fsl,ls1021a-qdma", > > + Or "fsl,ls1043a-qdma" followed by "fsl,ls1021a-qdma", > > It should be the other way around. Thanks for your review. It should be compatible = "fsl,ls1043a-qspi", "fsl,ls1021a-qspi"; I will update it in the next version. Thanks. ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v1 5/5] ARM: dts: ls1021a: add qDMA node 2016-08-18 6:38 [PATCH v1 0/5] dma: Add QorIQ qDMA engine driver support Yuan Yao ` (3 preceding siblings ...) 2016-08-18 6:38 ` [PATCH v1 4/5] ARM: dts: ls1043a: add qDMA node Yuan Yao @ 2016-08-18 6:38 ` Yuan Yao 4 siblings, 0 replies; 14+ messages in thread From: Yuan Yao @ 2016-08-18 6:38 UTC (permalink / raw) To: vinod.koul, robh+dt, dan.j.williams, mark.rutland, linux, shawnguo Cc: leoyang.li, dmaengine, linux-kernel, linux-arm-kernel, Yuan Yao From: Yuan Yao <yao.yuan@nxp.com> Add the QDMA node for ls1021a platform to support QDMA driver. Signed-off-by: Yuan Yao <yao.yuan@nxp.com> --- arch/arm/boot/dts/ls1021a.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 368e219..a1ca071 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -493,6 +493,16 @@ <&platform_clk 1>; }; + qdma: qdma@8390000 { + compatible = "fsl,ls1021a-qdma"; + reg = <0x0 0x8398000 0x0 0x2000 /* Controller regs */ + 0x0 0x839a000 0x0 0x2000>; /* Block regs */ + interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "qdma-error", "qdma-queue"; + big-endian; + }; + dcu: dcu@2ce0000 { compatible = "fsl,ls1021a-dcu"; reg = <0x0 0x2ce0000 0x0 0x10000>; -- 2.1.0.27.g96db324 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] dma: add Qualcomm Technologies HIDMA management driver
2015-10-30 3:08 ` Sinan Kaya
@ 2015-10-30 4:34 kbuild test robot
2015-10-30 3:08 ` Sinan Kaya
0 siblings, 1 reply; 14+ messages in thread
From: kbuild test robot @ 2015-10-30 4:34 UTC (permalink / raw)
To: Sinan Kaya
Cc: kbuild-all, dmaengine, timur, cov, jcm, Sinan Kaya, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Vinod Koul,
Dan Williams, devicetree, linux-kernel
Hi Sinan,
[auto build test WARNING on lwn/docs-next -- if it's inappropriate base, please suggest rules for selecting the more suitable base]
url: https://github.com/0day-ci/linux/commits/Sinan-Kaya/dma-add-Qualcomm-Technologies-HIDMA-management-driver/20151030-111408
coccinelle warnings: (new ones prefixed by >>)
>> drivers/dma/qcom_hidma_mgmt.c:852:3-8: No need to set .owner here. The core will do it.
Please review and possibly fold the followup patch.
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH 1/2] dma: add Qualcomm Technologies HIDMA management driver @ 2015-10-30 3:08 ` Sinan Kaya 2015-10-30 4:34 ` [PATCH] dma: fix platform_no_drv_owner.cocci warnings kbuild test robot 0 siblings, 1 reply; 14+ messages in thread From: Sinan Kaya @ 2015-10-30 3:08 UTC (permalink / raw) To: dmaengine, timur, cov, jcm Cc: Sinan Kaya, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Vinod Koul, Dan Williams, devicetree, linux-kernel The Qualcomm Technologies HIDMA device has been designed to support virtualization technology. The driver has been divided into two to follow the hardware design. The management driver is executed in hypervisor context and is the main managment for all channels provided by the device. The channel driver is exected in the guest OS context. Signed-off-by: Sinan Kaya <okaya@codeaurora.org> --- .../devicetree/bindings/dma/qcom_hidma_mgmt.txt | 42 + drivers/dma/Kconfig | 11 + drivers/dma/Makefile | 1 + drivers/dma/qcom_hidma_mgmt.c | 868 +++++++++++++++++++++ 4 files changed, 922 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt create mode 100644 drivers/dma/qcom_hidma_mgmt.c diff --git a/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt b/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt new file mode 100644 index 0000000..81674ab --- /dev/null +++ b/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt @@ -0,0 +1,42 @@ +Qualcomm Technologies HIDMA Management interface + +Required properties: +- compatible: must contain "qcom,hidma_mgmt" +- reg: Address range for DMA device +- interrupts: Should contain the one interrupt shared by all channels +- nr-channels: Number of channels supported by this DMA controller. +- max-write: Maximum write burst in bytes. A memcpy requested is + fragmented to multiples of this amount. +- max-read: Maximum read burst in bytes. A memcpy request is + fragmented to multiples of this amount. +- max-wxactions: Maximum write transactions to perform in a burst +- max-rdactions: Maximum read transactions to perform in a burst +- max-memset-limit: Maximum memset limit +- ch-priority-#n: Priority of the channel +- ch-weight-#n: Round robin weight of the channel +Example: + + hidma-mgmt@f9984000 = { + compatible = "qcom,hidma_mgmt"; + reg = <0xf9984000 0x15000>; + interrupts = <0 94 0>; + nr-channels = 6; + max-write = 1024; + max-read = 1024; + max-wxactions = 31; + max-rdactions = 31; + max-memset-limit = 8; + ch-priority-0 = 0; + ch-priority-1 = 1; + ch-priority-2 = 1; + ch-priority-3 = 0; + ch-priority-4 = 0; + ch-priority-5 = 0; + ch-weight-0 = 1; + ch-weight-1 = 13; + ch-weight-2 = 10; + ch-weight-3 = 3; + ch-weight-4 = 4; + ch-weight-5 = 5; + }; + diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index b458475..76a5a5e 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -501,6 +501,17 @@ config XGENE_DMA help Enable support for the APM X-Gene SoC DMA engine. +config QCOM_HIDMA_MGMT + bool "Qualcomm Technologies HIDMA Managment support" + select DMA_ENGINE + help + Enable support for the Qualcomm Technologies HIDMA Management. + Each DMA device requires one management interface driver + for basic initialization before QCOM_HIDMA driver can start + managing the channels. In a virtualized environment, the guest + OS would run QCOM_HIDMA driver and the hypervisor would run + the QCOM_HIDMA_MGMT driver. + config XILINX_VDMA tristate "Xilinx AXI VDMA Engine" depends on (ARCH_ZYNQ || MICROBLAZE) diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 7711a71..3d25ffd 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_PL330_DMA) += pl330.o obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ obj-$(CONFIG_PXA_DMA) += pxa_dma.o obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o +obj-$(CONFIG_QCOM_HIDMA_MGMT) += qcom_hidma_mgmt.o obj-$(CONFIG_RENESAS_DMA) += sh/ obj-$(CONFIG_SIRF_DMA) += sirf-dma.o obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o diff --git a/drivers/dma/qcom_hidma_mgmt.c b/drivers/dma/qcom_hidma_mgmt.c new file mode 100644 index 0000000..8fcad4d --- /dev/null +++ b/drivers/dma/qcom_hidma_mgmt.c @@ -0,0 +1,868 @@ +/* + * Qualcomm Technologies HIDMA DMA engine Management interface + * + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/dmaengine.h> +#include <linux/acpi.h> +#include <linux/of.h> +#include <linux/property.h> +#include <linux/debugfs.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/uaccess.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include "qcom_hidma.h" + +#define MHICFG_OFFSET 0x10 +#define QOS_N_OFFSET 0x300 +#define CFG_OFFSET 0x400 +#define HW_PARAM_OFFSET 0x408 +#define MAX_BUS_REQ_LEN_OFFSET 0x41C +#define MAX_XACTIONS_OFFSET 0x420 +#define SW_VERSION_OFFSET 0x424 +#define CHRESET_TIMEOUUT_OFFSET 0x500 +#define MEMSET_LIMIT_OFFSET 0x600 +#define MHID_BUS_ERR0_OFFSET 0x1020 +#define MHID_BUS_ERR1_OFFSET 0x1024 +#define MHID_BUS_ERR_CLR_OFFSET 0x102C +#define EVT_BUS_ERR0_OFFSET 0x1030 +#define EVT_BUS_ERR1_OFFSET 0x1034 +#define EVT_BUS_ERR_CLR_OFFSET 0x103C +#define IDE_BUS_ERR0_OFFSET 0x1040 +#define IDE_BUS_ERR1_OFFSET 0x1044 +#define IDE_BUS_ERR2_OFFSET 0x1048 +#define IDE_BUS_ERR_CLR_OFFSET 0x104C +#define ODE_BUS_ERR0_OFFSET 0x1050 +#define ODE_BUS_ERR1_OFFSET 0x1054 +#define ODE_BUS_ERR2_OFFSET 0x1058 +#define ODE_BUS_ERR_CLR_OFFSET 0x105C +#define MSI_BUS_ERR0_OFFSET 0x1060 +#define MSI_BUS_ERR_CLR_OFFSET 0x106C +#define TRE_ERR0_OFFSET 0x1070 +#define TRE_ERR_CLR_OFFSET 0x107C +#define HW_EVENTS_CFG_OFFSET 0x1080 + +#define HW_EVENTS_CFG_MASK 0xFF +#define TRE_ERR_TRCHID_MASK 0xF +#define TRE_ERR_EVRIDX_MASK 0xFF +#define TRE_ERR_TYPE_MASK 0xFF +#define MSI_ERR_RESP_MASK 0xFF +#define MSI_ERR_TRCHID_MASK 0xFF +#define ODE_ERR_REQLEN_MASK 0xFFFF +#define ODE_ERR_RESP_MASK 0xFF +#define ODE_ERR_TRCHID_MASK 0xFF +#define IDE_ERR_REQLEN_MASK 0xFFFF +#define IDE_ERR_RESP_MASK 0xFF +#define IDE_ERR_TRCHID_MASK 0xFF +#define EVT_ERR_RESP_MASK 0xFF +#define EVT_ERR_TRCHID_MASK 0xFF +#define MHID_ERR_RESP_MASK 0xFF +#define MHID_ERR_TRCHID_MASK 0xFF +#define MEMSET_LIMIT_MASK 0x1F +#define MAX_WR_XACTIONS_MASK 0x1F +#define MAX_RD_XACTIONS_MASK 0x1F +#define MAX_JOBSIZE_MASK 0xFF +#define MAX_COIDX_MASK 0xFF +#define TREQ_CAPACITY_MASK 0xFF +#define WEIGHT_MASK 0x7F +#define TREQ_LIMIT_MASK 0x1FF +#define NR_CHANNEL_MASK 0xFFFF +#define MAX_BUS_REQ_LEN_MASK 0xFFFF +#define CHRESET_TIMEOUUT_MASK 0xFFFFF + +#define TRE_ERR_TRCHID_BIT_POS 28 +#define TRE_ERR_IEOB_BIT_POS 16 +#define TRE_ERR_EVRIDX_BIT_POS 8 +#define MSI_ERR_RESP_BIT_POS 8 +#define ODE_ERR_REQLEN_BIT_POS 16 +#define ODE_ERR_RESP_BIT_POS 8 +#define IDE_ERR_REQLEN_BIT_POS 16 +#define IDE_ERR_RESP_BIT_POS 8 +#define EVT_ERR_RESP_BIT_POS 8 +#define MHID_ERR_RESP_BIT_POS 8 +#define MAX_WR_XACTIONS_BIT_POS 16 +#define TREQ_CAPACITY_BIT_POS 8 +#define MAX_JOB_SIZE_BIT_POS 16 +#define NR_EV_CHANNEL_BIT_POS 16 +#define MAX_BUS_WR_REQ_BIT_POS 16 +#define WRR_BIT_POS 8 +#define PRIORITY_BIT_POS 15 +#define TREQ_LIMIT_BIT_POS 16 +#define TREQ_LIMIT_EN_BIT_POS 23 +#define STOP_BIT_POS 24 + +#define MODULE_NAME "hidma-mgmt" +#define PREFIX MODULE_NAME ": " +#define AUTOSUSPEND_TIMEOUT 2000 + +#define HIDMA_RUNTIME_GET(dmadev) \ +do { \ + atomic_inc(&(dmadev)->pm_counter); \ + TRC_PM(&(dmadev)->pdev->dev, \ + "%s:%d pm_runtime_get %d\n", __func__, __LINE__,\ + atomic_read(&(dmadev)->pm_counter)); \ + pm_runtime_get_sync(&(dmadev)->pdev->dev); \ +} while (0) + +#define HIDMA_RUNTIME_SET(dmadev) \ +do { \ + atomic_dec(&(dmadev)->pm_counter); \ + TRC_PM(&(dmadev)->pdev->dev, \ + "%s:%d pm_runtime_put_autosuspend:%d\n", \ + __func__, __LINE__, \ + atomic_read(&(dmadev)->pm_counter)); \ + pm_runtime_mark_last_busy(&(dmadev)->pdev->dev); \ + pm_runtime_put_autosuspend(&(dmadev)->pdev->dev); \ +} while (0) + +struct qcom_hidma_mgmt_dev { + u8 max_wr_xactions; + u8 max_rd_xactions; + u8 max_memset_limit; + u16 max_write_request; + u16 max_read_request; + u16 nr_channels; + u32 chreset_timeout; + u32 sw_version; + u8 *priority; + u8 *weight; + + atomic_t pm_counter; + /* Hardware device constants */ + dma_addr_t dev_physaddr; + void __iomem *dev_virtaddr; + resource_size_t dev_addrsize; + + struct dentry *debugfs; + struct dentry *info; + struct dentry *err; + struct dentry *mhid_errclr; + struct dentry *evt_errclr; + struct dentry *ide_errclr; + struct dentry *ode_errclr; + struct dentry *msi_errclr; + struct dentry *tre_errclr; + struct dentry *evt_ena; + struct platform_device *pdev; +}; + +static unsigned int debug_pm; +module_param(debug_pm, uint, 0644); +MODULE_PARM_DESC(debug_pm, + "debug runtime power management transitions (default: 0)"); + +#define TRC_PM(...) do { \ + if (debug_pm) \ + dev_info(__VA_ARGS__); \ + } while (0) + + +#if IS_ENABLED(CONFIG_DEBUG_FS) + +#define HIDMA_SHOW(dma, name) \ + seq_printf(s, #name "=0x%x\n", dma->name) + +#define HIDMA_READ_SHOW(dma, name, offset) \ + do { \ + u32 val; \ + val = readl(dma->dev_virtaddr + offset); \ + seq_printf(s, name "=0x%x\n", val); \ + } while (0) + +/** + * qcom_hidma_mgmt_info: display HIDMA device info + * + * Display the info for the current HIDMA device. + */ +static int qcom_hidma_mgmt_info(struct seq_file *s, void *unused) +{ + struct qcom_hidma_mgmt_dev *mgmtdev = s->private; + u32 val; + int i; + + HIDMA_RUNTIME_GET(mgmtdev); + HIDMA_SHOW(mgmtdev, sw_version); + + val = readl(mgmtdev->dev_virtaddr + CFG_OFFSET); + seq_printf(s, "ENABLE=%d\n", val & 0x1); + + val = readl(mgmtdev->dev_virtaddr + CHRESET_TIMEOUUT_OFFSET); + seq_printf(s, "reset_timeout=%d\n", val & CHRESET_TIMEOUUT_MASK); + + val = readl(mgmtdev->dev_virtaddr + MHICFG_OFFSET); + seq_printf(s, "nr_event_channel=%d\n", + (val >> NR_EV_CHANNEL_BIT_POS) & NR_CHANNEL_MASK); + seq_printf(s, "nr_tr_channel=%d\n", (val & NR_CHANNEL_MASK)); + seq_printf(s, "nr_virt_tr_channel=%d\n", mgmtdev->nr_channels); + seq_printf(s, "dev_virtaddr=%p\n", &mgmtdev->dev_virtaddr); + seq_printf(s, "dev_physaddr=%pap\n", &mgmtdev->dev_physaddr); + seq_printf(s, "dev_addrsize=%pap\n", &mgmtdev->dev_addrsize); + + val = readl(mgmtdev->dev_virtaddr + MEMSET_LIMIT_OFFSET); + seq_printf(s, "MEMSET_LIMIT_OFFSET=%d\n", val & MEMSET_LIMIT_MASK); + + val = readl(mgmtdev->dev_virtaddr + HW_PARAM_OFFSET); + seq_printf(s, "MAX_JOB_SIZE=%d\n", + (val >> MAX_JOB_SIZE_BIT_POS) & MAX_JOBSIZE_MASK); + seq_printf(s, "TREQ_CAPACITY=%d\n", + (val >> TREQ_CAPACITY_BIT_POS) & TREQ_CAPACITY_MASK); + seq_printf(s, "MAX_COIDX_DEPTH=%d\n", val & MAX_COIDX_MASK); + + val = readl(mgmtdev->dev_virtaddr + MAX_BUS_REQ_LEN_OFFSET); + seq_printf(s, "MAX_BUS_WR_REQ_LEN=%d\n", + (val >> MAX_BUS_WR_REQ_BIT_POS) & MAX_BUS_REQ_LEN_MASK); + seq_printf(s, "MAX_BUS_RD_REQ_LEN=%d\n", val & MAX_BUS_REQ_LEN_MASK); + + val = readl(mgmtdev->dev_virtaddr + MAX_XACTIONS_OFFSET); + seq_printf(s, "MAX_WR_XACTIONS=%d\n", + (val >> MAX_WR_XACTIONS_BIT_POS) & MAX_WR_XACTIONS_MASK); + seq_printf(s, "MAX_RD_XACTIONS=%d\n", val & MAX_RD_XACTIONS_MASK); + + for (i = 0; i < mgmtdev->nr_channels; i++) { + void __iomem *offset; + + offset = mgmtdev->dev_virtaddr + QOS_N_OFFSET + (4 * i); + val = readl(offset); + + seq_printf(s, "CH#%d STOP=%d\n", + i, (val & (1 << STOP_BIT_POS)) ? 1 : 0); + seq_printf(s, "CH#%d TREQ LIMIT EN=%d\n", i, + (val & (1 << TREQ_LIMIT_EN_BIT_POS)) ? 1 : 0); + seq_printf(s, "CH#%d TREQ LIMIT=%d\n", + i, (val >> TREQ_LIMIT_BIT_POS) & TREQ_LIMIT_MASK); + seq_printf(s, "CH#%d priority=%d\n", i, + (val & (1 << PRIORITY_BIT_POS)) ? 1 : 0); + seq_printf(s, "CH#%d WRR=%d\n", i, + (val >> WRR_BIT_POS) & WEIGHT_MASK); + seq_printf(s, "CH#%d USE_DLA=%d\n", i, (val & 1) ? 1 : 0); + } + HIDMA_RUNTIME_SET(mgmtdev); + + return 0; +} + +static int qcom_hidma_mgmt_info_open(struct inode *inode, struct file *file) +{ + return single_open(file, qcom_hidma_mgmt_info, inode->i_private); +} + +static const struct file_operations qcom_hidma_mgmt_fops = { + .open = qcom_hidma_mgmt_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** + * qcom_hidma_mgmt_err: display HIDMA error info + * + * Display the error info for the current HIDMA device. + */ +static int qcom_hidma_mgmt_err(struct seq_file *s, void *unused) +{ + u32 val; + struct qcom_hidma_mgmt_dev *mgmtdev = s->private; + + HIDMA_RUNTIME_GET(mgmtdev); + val = readl(mgmtdev->dev_virtaddr + MHID_BUS_ERR0_OFFSET); + seq_printf(s, "MHID TR_CHID=%d\n", val & MHID_ERR_TRCHID_MASK); + seq_printf(s, "MHID RESP_ERROR=%d\n", + (val >> MHID_ERR_RESP_BIT_POS) & MHID_ERR_RESP_MASK); + HIDMA_READ_SHOW(mgmtdev, "MHID READ_PTR", MHID_BUS_ERR1_OFFSET); + + val = readl(mgmtdev->dev_virtaddr + EVT_BUS_ERR0_OFFSET); + seq_printf(s, "EVT TR_CHID=%d\n", val & EVT_ERR_TRCHID_MASK); + seq_printf(s, "EVT RESP_ERROR=%d\n", + (val >> EVT_ERR_RESP_BIT_POS) & EVT_ERR_RESP_MASK); + HIDMA_READ_SHOW(mgmtdev, "EVT WRITE_PTR", EVT_BUS_ERR1_OFFSET); + + val = readl(mgmtdev->dev_virtaddr + IDE_BUS_ERR0_OFFSET); + seq_printf(s, "IDE TR_CHID=%d\n", val & IDE_ERR_TRCHID_MASK); + seq_printf(s, "IDE RESP_ERROR=%d\n", + (val >> IDE_ERR_RESP_BIT_POS) & IDE_ERR_RESP_MASK); + seq_printf(s, "IDE REQ_LENGTH=%d\n", + (val >> IDE_ERR_REQLEN_BIT_POS) & IDE_ERR_REQLEN_MASK); + HIDMA_READ_SHOW(mgmtdev, "IDE ADDR_LSB", IDE_BUS_ERR1_OFFSET); + HIDMA_READ_SHOW(mgmtdev, "IDE ADDR_MSB", IDE_BUS_ERR2_OFFSET); + + val = readl(mgmtdev->dev_virtaddr + ODE_BUS_ERR0_OFFSET); + seq_printf(s, "ODE TR_CHID=%d\n", val & ODE_ERR_TRCHID_MASK); + seq_printf(s, "ODE RESP_ERROR=%d\n", + (val >> ODE_ERR_RESP_BIT_POS) & ODE_ERR_RESP_MASK); + seq_printf(s, "ODE REQ_LENGTH=%d\n", + (val >> ODE_ERR_REQLEN_BIT_POS) & ODE_ERR_REQLEN_MASK); + HIDMA_READ_SHOW(mgmtdev, "ODE ADDR_LSB", ODE_BUS_ERR1_OFFSET); + HIDMA_READ_SHOW(mgmtdev, "ODE ADDR_MSB", ODE_BUS_ERR2_OFFSET); + + val = readl(mgmtdev->dev_virtaddr + MSI_BUS_ERR0_OFFSET); + seq_printf(s, "MSI TR_CHID=%d\n", val & MSI_ERR_TRCHID_MASK); + seq_printf(s, "MSI RESP_ERROR=%d\n", + (val >> MSI_ERR_RESP_BIT_POS) & MSI_ERR_RESP_MASK); + + val = readl(mgmtdev->dev_virtaddr + TRE_ERR0_OFFSET); + seq_printf(s, "TRE TRE_TYPE=%d\n", val & TRE_ERR_TYPE_MASK); + seq_printf(s, "TRE TRE_EVRIDX=%d\n", + (val >> TRE_ERR_EVRIDX_BIT_POS) & TRE_ERR_EVRIDX_MASK); + seq_printf(s, "TRE TRE_IEOB=%d\n", + (val >> TRE_ERR_IEOB_BIT_POS) & 1); + seq_printf(s, "TRE TRCHID=%d\n", + (val >> TRE_ERR_TRCHID_BIT_POS) & TRE_ERR_TRCHID_MASK); + + HIDMA_READ_SHOW(mgmtdev, "HW_EVENTS_CFG_OFFSET", + HW_EVENTS_CFG_OFFSET); + + HIDMA_RUNTIME_SET(mgmtdev); + return 0; +} + +static int qcom_hidma_mgmt_err_open(struct inode *inode, struct file *file) +{ + return single_open(file, qcom_hidma_mgmt_err, inode->i_private); +} + +static const struct file_operations qcom_hidma_mgmt_err_fops = { + .open = qcom_hidma_mgmt_err_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static ssize_t qcom_hidma_mgmt_mhiderr_clr(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct qcom_hidma_mgmt_dev *mgmtdev = file->f_inode->i_private; + + HIDMA_RUNTIME_GET(mgmtdev); + writel(1, mgmtdev->dev_virtaddr + MHID_BUS_ERR_CLR_OFFSET); + HIDMA_RUNTIME_SET(mgmtdev); + return count; +} + +static const struct file_operations qcom_hidma_mgmt_mhiderr_clrfops = { + .write = qcom_hidma_mgmt_mhiderr_clr, +}; + +static ssize_t qcom_hidma_mgmt_evterr_clr(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct qcom_hidma_mgmt_dev *mgmtdev = file->f_inode->i_private; + + HIDMA_RUNTIME_GET(mgmtdev); + writel(1, mgmtdev->dev_virtaddr + EVT_BUS_ERR_CLR_OFFSET); + HIDMA_RUNTIME_SET(mgmtdev); + return count; +} + +static const struct file_operations qcom_hidma_mgmt_evterr_clrfops = { + .write = qcom_hidma_mgmt_evterr_clr, +}; + +static ssize_t qcom_hidma_mgmt_ideerr_clr(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct qcom_hidma_mgmt_dev *mgmtdev = file->f_inode->i_private; + + HIDMA_RUNTIME_GET(mgmtdev); + writel(1, mgmtdev->dev_virtaddr + IDE_BUS_ERR_CLR_OFFSET); + HIDMA_RUNTIME_SET(mgmtdev); + return count; +} + +static const struct file_operations qcom_hidma_mgmt_ideerr_clrfops = { + .write = qcom_hidma_mgmt_ideerr_clr, +}; + +static ssize_t qcom_hidma_mgmt_odeerr_clr(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct qcom_hidma_mgmt_dev *mgmtdev = file->f_inode->i_private; + + HIDMA_RUNTIME_GET(mgmtdev); + writel(1, mgmtdev->dev_virtaddr + ODE_BUS_ERR_CLR_OFFSET); + HIDMA_RUNTIME_SET(mgmtdev); + return count; +} + +static const struct file_operations qcom_hidma_mgmt_odeerr_clrfops = { + .write = qcom_hidma_mgmt_odeerr_clr, +}; + +static ssize_t qcom_hidma_mgmt_msierr_clr(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct qcom_hidma_mgmt_dev *mgmtdev = file->f_inode->i_private; + + HIDMA_RUNTIME_GET(mgmtdev); + writel(1, mgmtdev->dev_virtaddr + MSI_BUS_ERR_CLR_OFFSET); + HIDMA_RUNTIME_SET(mgmtdev); + return count; +} + +static const struct file_operations qcom_hidma_mgmt_msierr_clrfops = { + .write = qcom_hidma_mgmt_msierr_clr, +}; + +static ssize_t qcom_hidma_mgmt_treerr_clr(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct qcom_hidma_mgmt_dev *mgmtdev = file->f_inode->i_private; + + HIDMA_RUNTIME_GET(mgmtdev); + writel(1, mgmtdev->dev_virtaddr + TRE_ERR_CLR_OFFSET); + HIDMA_RUNTIME_SET(mgmtdev); + return count; +} + +static const struct file_operations qcom_hidma_mgmt_treerr_clrfops = { + .write = qcom_hidma_mgmt_treerr_clr, +}; + +static ssize_t qcom_hidma_mgmt_evtena(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char temp_buf[16+1]; + struct qcom_hidma_mgmt_dev *mgmtdev = file->f_inode->i_private; + u32 event; + ssize_t ret; + unsigned long val; + + temp_buf[16] = '\0'; + if (copy_from_user(temp_buf, user_buf, min_t(int, count, 16))) + goto out; + + ret = kstrtoul(temp_buf, 16, &val); + if (ret) { + pr_warn(PREFIX "unknown event\n"); + goto out; + } + + event = (u32)val & HW_EVENTS_CFG_MASK; + + HIDMA_RUNTIME_GET(mgmtdev); + writel(event, mgmtdev->dev_virtaddr + HW_EVENTS_CFG_OFFSET); + HIDMA_RUNTIME_SET(mgmtdev); +out: + return count; +} + +static const struct file_operations qcom_hidma_mgmt_evtena_fops = { + .write = qcom_hidma_mgmt_evtena, +}; + +static void qcom_hidma_mgmt_debug_uninit(struct qcom_hidma_mgmt_dev *mgmtdev) +{ + debugfs_remove(mgmtdev->evt_ena); + debugfs_remove(mgmtdev->tre_errclr); + debugfs_remove(mgmtdev->msi_errclr); + debugfs_remove(mgmtdev->ode_errclr); + debugfs_remove(mgmtdev->ide_errclr); + debugfs_remove(mgmtdev->evt_errclr); + debugfs_remove(mgmtdev->mhid_errclr); + debugfs_remove(mgmtdev->err); + debugfs_remove(mgmtdev->info); + debugfs_remove(mgmtdev->debugfs); +} + +static int qcom_hidma_mgmt_debug_init(struct qcom_hidma_mgmt_dev *mgmtdev) +{ + int rc = 0; + + mgmtdev->debugfs = debugfs_create_dir(dev_name(&mgmtdev->pdev->dev), + NULL); + if (!mgmtdev->debugfs) { + rc = -ENODEV; + return rc; + } + + mgmtdev->info = debugfs_create_file("info", S_IRUGO, + mgmtdev->debugfs, mgmtdev, &qcom_hidma_mgmt_fops); + if (!mgmtdev->info) { + rc = -ENOMEM; + goto cleanup; + } + + mgmtdev->err = debugfs_create_file("err", S_IRUGO, + mgmtdev->debugfs, mgmtdev, + &qcom_hidma_mgmt_err_fops); + if (!mgmtdev->err) { + rc = -ENOMEM; + goto cleanup; + } + + mgmtdev->mhid_errclr = debugfs_create_file("mhiderrclr", S_IWUSR, + mgmtdev->debugfs, mgmtdev, + &qcom_hidma_mgmt_mhiderr_clrfops); + if (!mgmtdev->mhid_errclr) { + rc = -ENOMEM; + goto cleanup; + } + + mgmtdev->evt_errclr = debugfs_create_file("evterrclr", S_IWUSR, + mgmtdev->debugfs, mgmtdev, + &qcom_hidma_mgmt_evterr_clrfops); + if (!mgmtdev->evt_errclr) { + rc = -ENOMEM; + goto cleanup; + } + + mgmtdev->ide_errclr = debugfs_create_file("ideerrclr", S_IWUSR, + mgmtdev->debugfs, mgmtdev, + &qcom_hidma_mgmt_ideerr_clrfops); + if (!mgmtdev->ide_errclr) { + rc = -ENOMEM; + goto cleanup; + } + + mgmtdev->ode_errclr = debugfs_create_file("odeerrclr", S_IWUSR, + mgmtdev->debugfs, mgmtdev, + &qcom_hidma_mgmt_odeerr_clrfops); + if (!mgmtdev->ode_errclr) { + rc = -ENOMEM; + goto cleanup; + } + + mgmtdev->msi_errclr = debugfs_create_file("msierrclr", S_IWUSR, + mgmtdev->debugfs, mgmtdev, + &qcom_hidma_mgmt_msierr_clrfops); + if (!mgmtdev->msi_errclr) { + rc = -ENOMEM; + goto cleanup; + } + + mgmtdev->tre_errclr = debugfs_create_file("treerrclr", S_IWUSR, + mgmtdev->debugfs, mgmtdev, + &qcom_hidma_mgmt_treerr_clrfops); + if (!mgmtdev->tre_errclr) { + rc = -ENOMEM; + goto cleanup; + } + + mgmtdev->evt_ena = debugfs_create_file("evtena", S_IWUSR, + mgmtdev->debugfs, mgmtdev, + &qcom_hidma_mgmt_evtena_fops); + if (!mgmtdev->evt_ena) { + rc = -ENOMEM; + goto cleanup; + } + + return 0; +cleanup: + qcom_hidma_mgmt_debug_uninit(mgmtdev); + return rc; +} +#else +static void qcom_hidma_mgmt_debug_uninit(struct qcom_hidma_mgmt_dev *mgmtdev) +{ +} +static int qcom_hidma_mgmt_debug_init(struct qcom_hidma_mgmt_dev *mgmtdev) +{ + return 0; +} +#endif + +static irqreturn_t qcom_hidma_mgmt_irq_handler(int irq, void *arg) +{ + /* TODO: handle irq here */ + return IRQ_HANDLED; +} + +static int qcom_hidma_mgmt_setup(struct qcom_hidma_mgmt_dev *mgmtdev) +{ + u32 val; + int i; + + val = readl(mgmtdev->dev_virtaddr + MAX_BUS_REQ_LEN_OFFSET); + + if (mgmtdev->max_write_request) { + val = val & + ~(MAX_BUS_REQ_LEN_MASK << MAX_BUS_WR_REQ_BIT_POS); + val = val | + (mgmtdev->max_write_request << MAX_BUS_WR_REQ_BIT_POS); + } + if (mgmtdev->max_read_request) { + val = val & ~(MAX_BUS_REQ_LEN_MASK); + val = val | (mgmtdev->max_read_request); + } + writel(val, mgmtdev->dev_virtaddr + MAX_BUS_REQ_LEN_OFFSET); + + val = readl(mgmtdev->dev_virtaddr + MAX_XACTIONS_OFFSET); + if (mgmtdev->max_wr_xactions) { + val = val & + ~(MAX_WR_XACTIONS_MASK << MAX_WR_XACTIONS_BIT_POS); + val = val | + (mgmtdev->max_wr_xactions << MAX_WR_XACTIONS_BIT_POS); + } + if (mgmtdev->max_rd_xactions) { + val = val & ~(MAX_RD_XACTIONS_MASK); + val = val | (mgmtdev->max_rd_xactions); + } + writel(val, mgmtdev->dev_virtaddr + MAX_XACTIONS_OFFSET); + + val = readl(mgmtdev->dev_virtaddr + MAX_BUS_REQ_LEN_OFFSET); + mgmtdev->max_write_request = + (val >> MAX_BUS_WR_REQ_BIT_POS) & MAX_BUS_REQ_LEN_MASK; + mgmtdev->max_read_request = val & MAX_BUS_REQ_LEN_MASK; + + val = readl(mgmtdev->dev_virtaddr + MAX_XACTIONS_OFFSET); + mgmtdev->max_wr_xactions = + (val >> MAX_WR_XACTIONS_BIT_POS) & MAX_WR_XACTIONS_MASK; + mgmtdev->max_rd_xactions = val & MAX_RD_XACTIONS_MASK; + + mgmtdev->sw_version = readl(mgmtdev->dev_virtaddr + SW_VERSION_OFFSET); + + for (i = 0; i < mgmtdev->nr_channels; i++) { + val = readl(mgmtdev->dev_virtaddr + QOS_N_OFFSET + (4 * i)); + val = val & ~(1 << PRIORITY_BIT_POS); + val = val | + ((mgmtdev->priority[i] & 0x1) << PRIORITY_BIT_POS); + val = val & ~(WEIGHT_MASK << WRR_BIT_POS); + val = val + | ((mgmtdev->weight[i] & WEIGHT_MASK) << WRR_BIT_POS); + writel(val, mgmtdev->dev_virtaddr + QOS_N_OFFSET + (4 * i)); + } + + if (mgmtdev->chreset_timeout > 0) { + val = readl(mgmtdev->dev_virtaddr + CHRESET_TIMEOUUT_OFFSET); + val = val & ~CHRESET_TIMEOUUT_MASK; + val = val | (mgmtdev->chreset_timeout & CHRESET_TIMEOUUT_MASK); + writel(val, mgmtdev->dev_virtaddr + CHRESET_TIMEOUUT_OFFSET); + } + val = readl(mgmtdev->dev_virtaddr + CHRESET_TIMEOUUT_OFFSET); + mgmtdev->chreset_timeout = val & CHRESET_TIMEOUUT_MASK; + + if (mgmtdev->max_memset_limit > 0) { + val = readl(mgmtdev->dev_virtaddr + MEMSET_LIMIT_OFFSET); + val = val & ~MEMSET_LIMIT_MASK; + val = val | (mgmtdev->max_memset_limit & MEMSET_LIMIT_MASK); + writel(val, mgmtdev->dev_virtaddr + MEMSET_LIMIT_OFFSET); + } + val = readl(mgmtdev->dev_virtaddr + MEMSET_LIMIT_OFFSET); + mgmtdev->max_memset_limit = val & MEMSET_LIMIT_MASK; + + val = readl(mgmtdev->dev_virtaddr + CFG_OFFSET); + val = val | 1; + writel(val, mgmtdev->dev_virtaddr + CFG_OFFSET); + + return 0; +} + +static int qcom_hidma_mgmt_probe(struct platform_device *pdev) +{ + struct resource *dma_resource; + int irq; + int rc, i; + struct qcom_hidma_mgmt_dev *mgmtdev; + + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + dma_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!dma_resource) { + dev_err(&pdev->dev, "No memory resources found\n"); + rc = -ENODEV; + goto out; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "irq resources not found\n"); + rc = -ENODEV; + goto out; + } + + mgmtdev = devm_kzalloc(&pdev->dev, sizeof(*mgmtdev), GFP_KERNEL); + if (!mgmtdev) { + rc = -ENOMEM; + goto out; + } + + mgmtdev->pdev = pdev; + HIDMA_RUNTIME_GET(mgmtdev); + + rc = devm_request_irq(&pdev->dev, irq, qcom_hidma_mgmt_irq_handler, + IRQF_SHARED, "qcom-hidmamgmt", mgmtdev); + if (rc) { + dev_err(&pdev->dev, "irq registration failed: %d\n", irq); + goto out; + } + + mgmtdev->dev_physaddr = dma_resource->start; + mgmtdev->dev_addrsize = resource_size(dma_resource); + + dev_dbg(&pdev->dev, "dev_physaddr:%pa\n", &mgmtdev->dev_physaddr); + dev_dbg(&pdev->dev, "dev_addrsize:%pa\n", &mgmtdev->dev_addrsize); + + mgmtdev->dev_virtaddr = devm_ioremap_resource(&pdev->dev, + dma_resource); + if (IS_ERR(mgmtdev->dev_virtaddr)) { + dev_err(&pdev->dev, "can't map i/o memory at %pa\n", + &mgmtdev->dev_physaddr); + rc = -ENOMEM; + goto out; + } + + if (device_property_read_u16(&pdev->dev, "nr-channels", + &mgmtdev->nr_channels)) { + dev_err(&pdev->dev, "number of channels missing\n"); + rc = -EINVAL; + goto out; + } + + device_property_read_u16(&pdev->dev, "max-write", + &mgmtdev->max_write_request); + if ((mgmtdev->max_write_request != 128) && + (mgmtdev->max_write_request != 256) && + (mgmtdev->max_write_request != 512) && + (mgmtdev->max_write_request != 1024)) { + dev_err(&pdev->dev, "invalid write request %d\n", + mgmtdev->max_write_request); + rc = -EINVAL; + goto out; + } + + device_property_read_u16(&pdev->dev, "max-read", + &mgmtdev->max_read_request); + if ((mgmtdev->max_read_request != 128) && + (mgmtdev->max_read_request != 256) && + (mgmtdev->max_read_request != 512) && + (mgmtdev->max_read_request != 1024)) { + dev_err(&pdev->dev, "invalid read request %d\n", + mgmtdev->max_read_request); + rc = -EINVAL; + goto out; + } + + device_property_read_u8(&pdev->dev, "max-wxactions", + &mgmtdev->max_wr_xactions); + + device_property_read_u8(&pdev->dev, "max-rdactions", + &mgmtdev->max_rd_xactions); + + device_property_read_u8(&pdev->dev, "max-memset-limit", + &mgmtdev->max_memset_limit); + + /* needs to be at least one */ + if (mgmtdev->max_memset_limit == 0) + mgmtdev->max_memset_limit = 1; + + mgmtdev->priority = devm_kcalloc(&pdev->dev, + mgmtdev->nr_channels, sizeof(*mgmtdev->priority), GFP_KERNEL); + if (!mgmtdev->priority) { + rc = -ENOMEM; + goto out; + } + + mgmtdev->weight = devm_kcalloc(&pdev->dev, + mgmtdev->nr_channels, sizeof(*mgmtdev->weight), GFP_KERNEL); + if (!mgmtdev->weight) { + rc = -ENOMEM; + goto out; + } + + for (i = 0; i < mgmtdev->nr_channels; i++) { + char name[30]; + + sprintf(name, "ch-priority-%d", i); + device_property_read_u8(&pdev->dev, name, + &mgmtdev->priority[i]); + + sprintf(name, "ch-weight-%d", i); + device_property_read_u8(&pdev->dev, name, + &mgmtdev->weight[i]); + + if (mgmtdev->weight[i] > 15) { + dev_err(&pdev->dev, "max value of weight can be 15.\n"); + rc = -EINVAL; + goto out; + } + + /* weight needs to be at least one */ + if (mgmtdev->weight[i] == 0) + mgmtdev->weight[i] = 1; + } + + rc = qcom_hidma_mgmt_setup(mgmtdev); + if (rc) { + dev_err(&pdev->dev, "setup failed\n"); + goto out; + } + + rc = qcom_hidma_mgmt_debug_init(mgmtdev); + if (rc) { + dev_err(&pdev->dev, "debugfs init failed\n"); + goto out; + } + + dev_info(&pdev->dev, + "HI-DMA engine management driver registration complete\n"); + platform_set_drvdata(pdev, mgmtdev); + HIDMA_RUNTIME_SET(mgmtdev); + return 0; +out: + pm_runtime_disable(&pdev->dev); + pm_runtime_put_sync_suspend(&pdev->dev); + return rc; +} + +static int qcom_hidma_mgmt_remove(struct platform_device *pdev) +{ + struct qcom_hidma_mgmt_dev *mgmtdev = platform_get_drvdata(pdev); + + HIDMA_RUNTIME_GET(mgmtdev); + qcom_hidma_mgmt_debug_uninit(mgmtdev); + pm_runtime_put_sync_suspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + dev_info(&pdev->dev, "HI-DMA engine management driver removed\n"); + return 0; +} + +#if IS_ENABLED(CONFIG_ACPI) +static const struct acpi_device_id qcom_hidma_mgmt_acpi_ids[] = { + {"QCOM8060"}, + {}, +}; +#endif + +static const struct of_device_id qcom_hidma_mgmt_match[] = { + { .compatible = "qcom,hidma_mgmt", }, + {}, +}; +MODULE_DEVICE_TABLE(of, qcom_hidma_mgmt_match); + +static struct platform_driver qcom_hidma_mgmt_driver = { + .probe = qcom_hidma_mgmt_probe, + .remove = qcom_hidma_mgmt_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(qcom_hidma_mgmt_match), + .acpi_match_table = ACPI_PTR(qcom_hidma_mgmt_acpi_ids), + }, +}; + +static int __init qcom_hidma_mgmt_init(void) +{ + return platform_driver_register(&qcom_hidma_mgmt_driver); +} +device_initcall(qcom_hidma_mgmt_init); + +static void __exit qcom_hidma_mgmt_exit(void) +{ + platform_driver_unregister(&qcom_hidma_mgmt_driver); +} +module_exit(qcom_hidma_mgmt_exit); -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH] dma: fix platform_no_drv_owner.cocci warnings 2015-10-30 3:08 ` Sinan Kaya @ 2015-10-30 4:34 ` kbuild test robot 0 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2015-10-30 4:34 UTC (permalink / raw) To: Sinan Kaya Cc: kbuild-all, dmaengine, timur, cov, jcm, Sinan Kaya, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Vinod Koul, Dan Williams, devicetree, linux-kernel drivers/dma/qcom_hidma_mgmt.c:852:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Sinan Kaya <okaya@codeaurora.org> Signed-off-by: Fengguang Wu <fengguang.wu@intel.com> --- qcom_hidma_mgmt.c | 1 - 1 file changed, 1 deletion(-) --- a/drivers/dma/qcom_hidma_mgmt.c +++ b/drivers/dma/qcom_hidma_mgmt.c @@ -849,7 +849,6 @@ static struct platform_driver qcom_hidma .remove = qcom_hidma_mgmt_remove, .driver = { .name = MODULE_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(qcom_hidma_mgmt_match), .acpi_match_table = ACPI_PTR(qcom_hidma_mgmt_acpi_ids), }, ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2016-08-31 5:50 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-08-18 6:38 [PATCH v1 0/5] dma: Add QorIQ qDMA engine driver support Yuan Yao 2016-08-18 6:38 ` [PATCH v1 1/5] " Yuan Yao 2016-08-18 9:16 ` Russell King - ARM Linux 2016-08-24 3:39 ` Yao Yuan 2016-08-23 12:18 ` kbuild test robot 2016-08-23 12:18 ` [PATCH] dma: fix platform_no_drv_owner.cocci warnings kbuild test robot 2016-08-18 6:38 ` [PATCH v1 2/5] dma: Add device tree binding for QorIQ qDMA driver Yuan Yao 2016-08-18 6:38 ` [PATCH v1 3/5] MAINTAINERS: add maintainer entry for QorIQ QDMA driver Yuan Yao 2016-08-18 6:38 ` [PATCH v1 4/5] ARM: dts: ls1043a: add qDMA node Yuan Yao 2016-08-29 7:29 ` Alexander Stein 2016-08-29 7:34 ` Alexander Stein 2016-08-31 4:17 ` Yao Yuan 2016-08-18 6:38 ` [PATCH v1 5/5] ARM: dts: ls1021a: " Yuan Yao -- strict thread matches above, loose matches on Subject: below -- 2015-10-30 4:34 [PATCH 1/2] dma: add Qualcomm Technologies HIDMA management driver kbuild test robot 2015-10-30 3:08 ` Sinan Kaya 2015-10-30 4:34 ` [PATCH] dma: fix platform_no_drv_owner.cocci warnings kbuild test robot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®