Subject: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

This is the driver for the AXI Central Direct Memory Access (AXI
CDMA) core, which is a soft Xilinx IP core that provides high-bandwidth
Direct Memory Access (DMA) between a memory-mapped source address and a
memory-mapped destination address.

This module works on Zynq (ARM Based SoC) and Microblaze platforms.

Signed-off-by: Srikanth Thokala <[email protected]>
Signed-off-by: Kedareswara rao Appana <[email protected]>
---
This patch is rebased on the commit
Merge tag 'nfs-for-4.1-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Changes in v4:
- used GFP_NOWAIT instead of GFP_KERNEL during the desc allocation
- Modified spin_lock handling moved the spin_lock to the appropriate functions
- device_control api is removed and updated driver as per newer APi's.
Changes in v3:
- Check for CDMA idle condition before changing the configuration.
- Modified the xilinx_dma.h header file location to the
include/linux/dma/xilinx_dma.h
Changes in v2:
- Rebased on 3.16-rc7.

drivers/dma/Kconfig | 12 +
drivers/dma/xilinx/Makefile | 1 +
drivers/dma/xilinx/xilinx_cdma.c | 987 +++++++++++++++++++++++++++++++++++++++
include/linux/dma/xilinx_dma.h | 15 +-
4 files changed, 1014 insertions(+), 1 deletion(-)
create mode 100644 drivers/dma/xilinx/xilinx_cdma.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index bda2cb0..c42cf24 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -492,4 +492,16 @@ config QCOM_BAM_DMA
Enable support for the QCOM BAM DMA controller. This controller
provides DMA capabilities for a variety of on-chip devices.

+config XILINX_CDMA
+ tristate "Xilinx AXI CDMA Engine"
+ depends on (ARCH_ZYNQ || MICROBLAZE)
+ select DMA_ENGINE
+ help
+ Enable support for Xilinx AXI CDMA Soft IP.
+
+ The AXI CDMA is a soft IP which provides high-bandwidth
+ Direct Memory Access (DMA) between a memory-mapped source
+ address and a memory-mapped destination address using the
+ AXI4 protocol.
+
endif
diff --git a/drivers/dma/xilinx/Makefile b/drivers/dma/xilinx/Makefile
index 3c4e9f2..f909d34 100644
--- a/drivers/dma/xilinx/Makefile
+++ b/drivers/dma/xilinx/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_XILINX_VDMA) += xilinx_vdma.o
+obj-$(CONFIG_XILINX_VDMA) += xilinx_cdma.o
diff --git a/drivers/dma/xilinx/xilinx_cdma.c b/drivers/dma/xilinx/xilinx_cdma.c
new file mode 100644
index 0000000..eda443a
--- /dev/null
+++ b/drivers/dma/xilinx/xilinx_cdma.c
@@ -0,0 +1,987 @@
+/*
+ * DMA driver for Xilinx Central DMA Engine
+ *
+ * Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved.
+ *
+ * Based on the Freescale DMA driver.
+ *
+ * Description:
+ * The AXI CDMA, is a soft IP, which provides high-bandwidth Direct Memory
+ * Access (DMA) between a memory-mapped source address and a memory-mapped
+ * destination address.
+ *
+ * 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 <linux/bitops.h>
+#include <linux/dmapool.h>
+#include <linux/dma/xilinx_dma.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_dma.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#include "../dmaengine.h"
+
+/* Register Offsets */
+#define XILINX_CDMA_CONTROL_OFFSET 0x00
+#define XILINX_CDMA_STATUS_OFFSET 0x04
+#define XILINX_CDMA_CDESC_OFFSET 0x08
+#define XILINX_CDMA_TDESC_OFFSET 0x10
+#define XILINX_CDMA_SRCADDR_OFFSET 0x18
+#define XILINX_CDMA_DSTADDR_OFFSET 0x20
+#define XILINX_CDMA_BTT_OFFSET 0x28
+
+/* General register bits definitions */
+#define XILINX_CDMA_CR_RESET BIT(2)
+#define XILINX_CDMA_CR_SGMODE BIT(3)
+
+#define XILINX_CDMA_SR_IDLE BIT(1)
+
+#define XILINX_CDMA_XR_IRQ_IOC_MASK BIT(12)
+#define XILINX_CDMA_XR_IRQ_DELAY_MASK BIT(13)
+#define XILINX_CDMA_XR_IRQ_ERROR_MASK BIT(14)
+#define XILINX_CDMA_XR_IRQ_ALL_MASK GENMASK(14, 12)
+
+#define XILINX_CDMA_XR_DELAY_MASK GENMASK(31, 24)
+#define XILINX_CDMA_XR_COALESCE_MASK GENMASK(23, 16)
+
+#define XILINX_CDMA_DELAY_MAX GENMASK(7, 0)
+#define XILINX_CDMA_DELAY_SHIFT 24
+
+#define XILINX_CDMA_COALESCE_MAX GENMASK(7, 0)
+#define XILINX_CDMA_COALESCE_SHIFT 16
+
+/* Delay loop counter to prevent hardware failure */
+#define XILINX_CDMA_RESET_LOOP 1000000
+
+/* Maximum transfer length */
+#define XILINX_CDMA_MAX_TRANS_LEN GENMASK(22, 0)
+
+/**
+ * struct xilinx_cdma_desc_hw - Hardware Descriptor
+ * @next_desc: Next Descriptor Pointer @0x00
+ * @pad1: Reserved @0x04
+ * @src_addr: Source address @0x08
+ * @pad2: Reserved @0x0C
+ * @dest_addr: Destination address @0x10
+ * @pad3: Reserved @0x14
+ * @control: Control field @0x18
+ * @status: Status field @0x1C
+ */
+struct xilinx_cdma_desc_hw {
+ u32 next_desc;
+ u32 pad1;
+ u32 src_addr;
+ u32 pad2;
+ u32 dest_addr;
+ u32 pad3;
+ u32 control;
+ u32 status;
+} __aligned(64);
+
+/**
+ * struct xilinx_cdma_tx_segment - Descriptor segment
+ * @hw: Hardware descriptor
+ * @node: Node in the descriptor segments list
+ * @phys: Physical address of segment
+ */
+struct xilinx_cdma_tx_segment {
+ struct xilinx_cdma_desc_hw hw;
+ struct list_head node;
+ dma_addr_t phys;
+} __aligned(64);
+
+/**
+ * struct xilinx_cdma_tx_descriptor - Per Transaction structure
+ * @async_tx: Async transaction descriptor
+ * @segments: TX segments list
+ * @node: Node in the channel descriptors list
+ */
+struct xilinx_cdma_tx_descriptor {
+ struct dma_async_tx_descriptor async_tx;
+ struct list_head segments;
+ struct list_head node;
+};
+
+/**
+ * struct xilinx_cdma_chan - Driver specific cdma channel structure
+ * @xdev: Driver specific device structure
+ * @lock: Descriptor operation lock
+ * @done_list: Complete descriptors
+ * @pending_list: Descriptors waiting
+ * @active_desc: Active descriptor
+ * @common: DMA common channel
+ * @desc_pool: Descriptors pool
+ * @dev: The dma device
+ * @irq: Channel IRQ
+ * @has_sg: Support scatter transfers
+ * @err: Channel has errors
+ * @idle: Channel status
+ * @tasklet: Cleanup work after irq
+ */
+struct xilinx_cdma_chan {
+ struct xilinx_cdma_device *xdev;
+ spinlock_t lock;
+ struct list_head done_list;
+ struct list_head pending_list;
+ struct xilinx_cdma_tx_descriptor *active_desc;
+ struct dma_chan common;
+ struct dma_pool *desc_pool;
+ struct device *dev;
+ int irq;
+ bool has_sg;
+ int err;
+ bool idle;
+ struct tasklet_struct tasklet;
+};
+
+/**
+ * struct xilinx_cdma_device - CDMA device structure
+ * @regs: I/O mapped base address
+ * @dev: Device Structure
+ * @common: DMA device structure
+ * @chan: Driver specific cdma channel
+ * @has_sg: Specifies whether Scatter-Gather is present or not
+ */
+struct xilinx_cdma_device {
+ void __iomem *regs;
+ struct device *dev;
+ struct dma_device common;
+ struct xilinx_cdma_chan *chan;
+ bool has_sg;
+};
+
+/* Macros */
+#define to_xilinx_chan(chan) \
+ container_of(chan, struct xilinx_cdma_chan, common)
+#define to_cdma_tx_descriptor(tx) \
+ container_of(tx, struct xilinx_cdma_tx_descriptor, async_tx)
+
+/* IO accessors */
+static inline void cdma_write(struct xilinx_cdma_chan *chan, u32 reg, u32 val)
+{
+ writel(val, chan->xdev->regs + reg);
+}
+
+static inline u32 cdma_read(struct xilinx_cdma_chan *chan, u32 reg)
+{
+ return readl(chan->xdev->regs + reg);
+}
+
+static inline void cdma_ctrl_clr(struct xilinx_cdma_chan *chan, u32 reg,
+ u32 clr)
+{
+ cdma_write(chan, reg, cdma_read(chan, reg) & ~clr);
+}
+
+static inline void cdma_ctrl_set(struct xilinx_cdma_chan *chan, u32 reg,
+ u32 set)
+{
+ cdma_write(chan, reg, cdma_read(chan, reg) | set);
+}
+
+/* -----------------------------------------------------------------------------
+ * Descriptors and segments alloc and free
+ */
+
+/**
+ * xilinx_cdma_alloc_tx_segment - Allocate transaction segment
+ * @chan: Driver specific cdma channel
+ *
+ * Return: The allocated segment on success and NULL on failure.
+ */
+static struct xilinx_cdma_tx_segment *
+xilinx_cdma_alloc_tx_segment(struct xilinx_cdma_chan *chan)
+{
+ struct xilinx_cdma_tx_segment *segment;
+ dma_addr_t phys;
+
+ segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys);
+ if (!segment)
+ return NULL;
+
+ memset(segment, 0, sizeof(*segment));
+ segment->phys = phys;
+
+ return segment;
+}
+
+/**
+ * xilinx_cdma_free_tx_segment - Free transaction segment
+ * @chan: Driver specific cdma channel
+ * @segment: cdma transaction segment
+ */
+static void xilinx_cdma_free_tx_segment(struct xilinx_cdma_chan *chan,
+ struct xilinx_cdma_tx_segment *segment)
+{
+ dma_pool_free(chan->desc_pool, segment, segment->phys);
+}
+
+/**
+ * xilinx_cdma_tx_descriptor - Allocate transaction descriptor
+ * @chan: Driver specific cdma channel
+ *
+ * Return: The allocated descriptor on success and NULL on failure.
+ */
+static struct xilinx_cdma_tx_descriptor *
+xilinx_cdma_alloc_tx_descriptor(struct xilinx_cdma_chan *chan)
+{
+ struct xilinx_cdma_tx_descriptor *desc;
+
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return NULL;
+
+ INIT_LIST_HEAD(&desc->segments);
+
+ return desc;
+}
+
+/**
+ * xilinx_cdma_free_tx_descriptor - Free transaction descriptor
+ * @chan: Driver specific cdma channel
+ * @desc: cdma transaction descriptor
+ */
+static void
+xilinx_cdma_free_tx_descriptor(struct xilinx_cdma_chan *chan,
+ struct xilinx_cdma_tx_descriptor *desc)
+{
+ struct xilinx_cdma_tx_segment *segment, *next;
+
+ if (!desc)
+ return;
+
+ list_for_each_entry_safe(segment, next, &desc->segments, node) {
+ list_del(&segment->node);
+ xilinx_cdma_free_tx_segment(chan, segment);
+ }
+
+ kfree(desc);
+}
+
+/**
+ * xilinx_cdma_alloc_chan_resources - Allocate channel resources
+ * @dchan: DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_cdma_alloc_chan_resources(struct dma_chan *dchan)
+{
+ struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
+
+ /* Has this channel already been allocated? */
+ if (chan->desc_pool)
+ return 0;
+
+ /*
+ * We need the descriptor to be aligned to 64bytes
+ * for meeting Xilinx DMA specification requirement.
+ */
+ chan->desc_pool = dma_pool_create("xilinx_cdma_desc_pool",
+ chan->dev,
+ sizeof(struct xilinx_cdma_tx_segment),
+ __alignof__(struct xilinx_cdma_tx_segment), 0);
+ if (!chan->desc_pool) {
+ dev_err(chan->dev,
+ "unable to allocate channel descriptor pool\n");
+ return -ENOMEM;
+ }
+
+ dma_cookie_init(dchan);
+ return 0;
+}
+
+/**
+ * xilinx_cdma_free_desc_list - Free descriptors list
+ * @chan: Driver specific cdma channel
+ * @list: List to parse and delete the descriptor
+ */
+static void xilinx_cdma_free_desc_list(struct xilinx_cdma_chan *chan,
+ struct list_head *list)
+{
+ struct xilinx_cdma_tx_descriptor *desc, *next;
+
+ list_for_each_entry_safe(desc, next, list, node) {
+ list_del(&desc->node);
+ xilinx_cdma_free_tx_descriptor(chan, desc);
+ }
+}
+
+/**
+ * xilinx_cdma_free_chan_resources - Free channel resources
+ * @dchan: DMA channel
+ */
+static void xilinx_cdma_free_chan_resources(struct dma_chan *dchan)
+{
+ struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ xilinx_cdma_free_desc_list(chan, &chan->done_list);
+ xilinx_cdma_free_desc_list(chan, &chan->pending_list);
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ dma_pool_destroy(chan->desc_pool);
+ chan->desc_pool = NULL;
+}
+
+/**
+ * xilinx_cdma_chan_desc_cleanup - Clean channel descriptors
+ * @chan: Driver specific cdma channel
+ */
+static void xilinx_cdma_chan_desc_cleanup(struct xilinx_cdma_chan *chan)
+{
+ struct xilinx_cdma_tx_descriptor *desc, *next;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+ dma_async_tx_callback callback;
+ void *callback_param;
+
+ /* Remove from the list of running transactions */
+ list_del(&desc->node);
+
+ /* Run the link descriptor callback function */
+ callback = desc->async_tx.callback;
+ callback_param = desc->async_tx.callback_param;
+ if (callback) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ callback(callback_param);
+ spin_lock_irqsave(&chan->lock, flags);
+ }
+
+ /* Run any dependencies, then free the descriptor */
+ dma_run_dependencies(&desc->async_tx);
+ xilinx_cdma_free_tx_descriptor(chan, desc);
+ }
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_cdma_tx_status - Get CDMA transaction status
+ * @dchan: DMA channel
+ * @cookie: Transaction identifier
+ * @txstate: Transaction state
+ *
+ * Return: DMA transaction status
+ */
+static enum dma_status xilinx_tx_status(struct dma_chan *dchan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ return dma_cookie_status(dchan, cookie, txstate);
+}
+
+/**
+ * xilinx_cdma_is_idle - Check if cdma channel is idle
+ * @chan: Driver specific cdma channel
+ *
+ * Return: 'true' if idle, 'false' if not.
+ */
+static bool cdma_is_idle(struct xilinx_cdma_chan *chan)
+{
+ return cdma_read(chan, XILINX_CDMA_STATUS_OFFSET) & XILINX_CDMA_SR_IDLE;
+}
+
+/**
+ * xilinx_cdma_start_transfer - Starts cdma transfer
+ * @chan: Driver specific channel struct pointer
+ */
+static void xilinx_cdma_start_transfer(struct xilinx_cdma_chan *chan)
+{
+ struct xilinx_cdma_tx_descriptor *desc;
+ struct xilinx_cdma_tx_segment *head, *tail;
+
+ if (chan->err)
+ return;
+
+ if (list_empty(&chan->pending_list))
+ return;
+
+ if (!chan->idle)
+ return;
+
+ /* If hardware is busy, cannot submit */
+ if (chan->has_sg && !cdma_is_idle(chan)) {
+ tail = list_entry(desc->segments.prev,
+ struct xilinx_cdma_tx_segment, node);
+ cdma_write(chan, XILINX_CDMA_TDESC_OFFSET, tail->phys);
+ goto out_free_desc;
+ }
+
+ desc = list_first_entry(&chan->pending_list,
+ struct xilinx_cdma_tx_descriptor, node);
+
+ if (chan->has_sg) {
+ head = list_first_entry(&desc->segments,
+ struct xilinx_cdma_tx_segment, node);
+ tail = list_entry(desc->segments.prev,
+ struct xilinx_cdma_tx_segment, node);
+
+ cdma_write(chan, XILINX_CDMA_CDESC_OFFSET, head->phys);
+
+ /* Update tail ptr register which will start the transfer */
+ cdma_write(chan, XILINX_CDMA_TDESC_OFFSET, tail->phys);
+ } else {
+ /* In simple mode */
+ struct xilinx_cdma_tx_segment *segment;
+ struct xilinx_cdma_desc_hw *hw;
+
+ segment = list_first_entry(&desc->segments,
+ struct xilinx_cdma_tx_segment,
+ node);
+
+ hw = &segment->hw;
+
+ cdma_write(chan, XILINX_CDMA_SRCADDR_OFFSET, hw->src_addr);
+ cdma_write(chan, XILINX_CDMA_DSTADDR_OFFSET, hw->dest_addr);
+
+ /* Start the transfer */
+ cdma_write(chan, XILINX_CDMA_BTT_OFFSET,
+ hw->control & XILINX_CDMA_MAX_TRANS_LEN);
+ }
+
+out_free_desc:
+ list_del(&desc->node);
+ chan->idle = false;
+ chan->active_desc = desc;
+}
+
+/**
+ * xilinx_cdma_issue_pending - Issue pending transactions
+ * @dchan: DMA channel
+ */
+static void xilinx_cdma_issue_pending(struct dma_chan *dchan)
+{
+ struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ xilinx_cdma_start_transfer(chan);
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xilinx_cdma_complete_descriptor - Mark the active descriptor as complete
+ * @chan : xilinx DMA channel
+ */
+static void xilinx_cdma_complete_descriptor(struct xilinx_cdma_chan *chan)
+{
+ struct xilinx_cdma_tx_descriptor *desc;
+
+ desc = chan->active_desc;
+ if (!desc) {
+ dev_dbg(chan->dev, "no running descriptors\n");
+ return;
+ }
+
+ dma_cookie_complete(&desc->async_tx);
+ list_add_tail(&desc->node, &chan->done_list);
+
+ chan->active_desc = NULL;
+}
+
+/**
+ * xilinx_cdma_chan_reset - Reset CDMA channel
+ * @chan: Driver specific CDMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_cdma_chan_reset(struct xilinx_cdma_chan *chan)
+{
+ int loop = XILINX_CDMA_RESET_LOOP;
+ u32 tmp;
+
+ cdma_ctrl_set(chan, XILINX_CDMA_CONTROL_OFFSET,
+ XILINX_CDMA_CR_RESET);
+
+ tmp = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) &
+ XILINX_CDMA_CR_RESET;
+
+ /* Wait for the hardware to finish reset */
+ do {
+ tmp = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) &
+ XILINX_CDMA_CR_RESET;
+ } while (loop-- && tmp);
+
+ if (!loop) {
+ dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
+ cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET),
+ cdma_read(chan, XILINX_CDMA_STATUS_OFFSET));
+ return -EBUSY;
+ }
+
+ /* Enable interrupts */
+ cdma_ctrl_set(chan, XILINX_CDMA_CONTROL_OFFSET,
+ XILINX_CDMA_XR_IRQ_ALL_MASK);
+
+ /* Enable SG Mode */
+ if (chan->has_sg)
+ cdma_ctrl_set(chan, XILINX_CDMA_CONTROL_OFFSET,
+ XILINX_CDMA_CR_SGMODE);
+ return 0;
+}
+
+/**
+ * xilinx_cdma_irq_handler - CDMA Interrupt handler
+ * @irq: IRQ number
+ * @data: Pointer to the Xilinx CDMA channel structure
+ *
+ * Return: IRQ_HANDLED/IRQ_NONE
+ */
+static irqreturn_t xilinx_cdma_irq_handler(int irq, void *data)
+{
+ struct xilinx_cdma_chan *chan = data;
+ u32 status;
+
+ status = cdma_read(chan, XILINX_CDMA_STATUS_OFFSET);
+ if (!(status & XILINX_CDMA_XR_IRQ_ALL_MASK))
+ return IRQ_NONE;
+
+ /* Ack the interrupts */
+ cdma_write(chan, XILINX_CDMA_STATUS_OFFSET,
+ XILINX_CDMA_XR_IRQ_ALL_MASK);
+
+ if (status & XILINX_CDMA_XR_IRQ_ERROR_MASK) {
+ dev_err(chan->dev,
+ "Channel %x has errors %x, cdr %x tdr %x\n",
+ (u32)chan,
+ (u32)cdma_read(chan, XILINX_CDMA_STATUS_OFFSET),
+ (u32)cdma_read(chan, XILINX_CDMA_CDESC_OFFSET),
+ (u32)cdma_read(chan, XILINX_CDMA_TDESC_OFFSET));
+ chan->err = true;
+ }
+
+ /*
+ * Device takes too long to do the transfer when user requires
+ * responsiveness
+ */
+ if (status & XILINX_CDMA_XR_IRQ_DELAY_MASK)
+ dev_dbg(chan->dev, "Inter-packet latency too long\n");
+
+ if (status & XILINX_CDMA_XR_IRQ_IOC_MASK) {
+ spin_lock(&chan->lock);
+ xilinx_cdma_complete_descriptor(chan);
+ chan->idle = true;
+ xilinx_cdma_start_transfer(chan);
+ spin_unlock(&chan->lock);
+ }
+
+ tasklet_schedule(&chan->tasklet);
+ return IRQ_HANDLED;
+}
+
+/**
+ * xilinx_cdma_do_tasklet - Schedule completion tasklet
+ * @data: Pointer to the Xilinx cdma channel structure
+ */
+static void xilinx_cdma_do_tasklet(unsigned long data)
+{
+ struct xilinx_cdma_chan *chan = (struct xilinx_cdma_chan *)data;
+
+ xilinx_cdma_chan_desc_cleanup(chan);
+}
+
+/**
+ * xilinx_cdma_tx_submit - Submit DMA transaction
+ * @tx: Async transaction descriptor
+ *
+ * Return: cookie value on success and failure value on error
+ */
+static dma_cookie_t xilinx_cdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct xilinx_cdma_chan *chan = to_xilinx_chan(tx->chan);
+ struct xilinx_cdma_tx_descriptor *desc = to_cdma_tx_descriptor(tx);
+ dma_cookie_t cookie;
+ unsigned long flags;
+ int err;
+
+ if (chan->err) {
+ /*
+ * If reset fails, need to hard reset the system.
+ * Channel is no longer functional
+ */
+ err = xilinx_cdma_chan_reset(chan);
+ if (err < 0)
+ return err;
+ }
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ cookie = dma_cookie_assign(tx);
+
+ /* Append the transaction to the pending transactions queue. */
+ list_add_tail(&desc->node, &chan->pending_list);
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ return cookie;
+}
+
+/**
+ * xilinx_cdma_prep_memcpy - prepare descriptors for a memcpy transaction
+ * @dchan: DMA channel
+ * @dma_dst: destination address
+ * @dma_src: source address
+ * @len: transfer length
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *
+xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst,
+ dma_addr_t dma_src, size_t len, unsigned long flags)
+{
+ struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
+ struct xilinx_cdma_desc_hw *hw;
+ struct xilinx_cdma_tx_descriptor *desc;
+ struct xilinx_cdma_tx_segment *segment, *prev;
+
+ if (!len || len > XILINX_CDMA_MAX_TRANS_LEN)
+ return NULL;
+
+ desc = xilinx_cdma_alloc_tx_descriptor(chan);
+ if (!desc)
+ return NULL;
+
+ dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+ desc->async_tx.tx_submit = xilinx_cdma_tx_submit;
+ async_tx_ack(&desc->async_tx);
+
+ /* Allocate the link descriptor from DMA pool */
+ segment = xilinx_cdma_alloc_tx_segment(chan);
+ if (!segment)
+ goto error;
+
+ hw = &segment->hw;
+ hw->control = len;
+ hw->src_addr = dma_src;
+ hw->dest_addr = dma_dst;
+
+ /* Fill the previous next descriptor with current */
+ prev = list_last_entry(&desc->segments,
+ struct xilinx_cdma_tx_segment, node);
+ prev->hw.next_desc = segment->phys;
+
+ /* Insert the segment into the descriptor segments list. */
+ list_add_tail(&segment->node, &desc->segments);
+
+ prev = segment;
+
+ /* Link the last hardware descriptor with the first. */
+ segment = list_first_entry(&desc->segments,
+ struct xilinx_cdma_tx_segment, node);
+ prev->hw.next_desc = segment->phys;
+
+ return &desc->async_tx;
+
+error:
+ xilinx_cdma_free_tx_descriptor(chan, desc);
+ return NULL;
+}
+
+/**
+ * xilinx_cdma_terminate_all - Free the descriptors
+ * @dchan: DMA Channel pointer
+ *
+ * Return: '0' always
+ */
+static int xilinx_cdma_terminate_all(struct dma_chan *dchan)
+{
+ struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ /* Reset the channel */
+ xilinx_cdma_chan_reset(chan);
+
+ /* Remove and free all of the descriptors in the lists */
+ xilinx_cdma_free_desc_list(chan, &chan->pending_list);
+ xilinx_cdma_free_desc_list(chan, &chan->done_list);
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ return 0;
+}
+
+/**
+ * xilinx_cdma_channel_set_config - Configure cdma channel
+ * @dchan: DMA channel
+ * @cfg: cdma device configuration pointer
+ *
+ * Return: '0' on success and failure value on error
+ */
+int xilinx_cdma_channel_set_config(struct dma_chan *dchan,
+ struct xilinx_cdma_config *cfg)
+{
+ struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
+ u32 reg = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET);
+
+ if (!cdma_is_idle(chan))
+ return -EBUSY;
+
+ if (cfg->reset)
+ return xilinx_cdma_chan_reset(chan);
+
+ if (cfg->coalesc <= XILINX_CDMA_COALESCE_MAX) {
+ reg &= ~XILINX_CDMA_XR_COALESCE_MASK;
+ reg |= cfg->coalesc << XILINX_CDMA_COALESCE_SHIFT;
+ }
+
+ if (cfg->delay <= XILINX_CDMA_DELAY_MAX) {
+ reg &= ~XILINX_CDMA_XR_DELAY_MASK;
+ reg |= cfg->delay << XILINX_CDMA_DELAY_SHIFT;
+ }
+
+ cdma_write(chan, XILINX_CDMA_CONTROL_OFFSET, reg);
+
+ return 0;
+}
+EXPORT_SYMBOL(xilinx_cdma_channel_set_config);
+
+/* -----------------------------------------------------------------------------
+ * Probe and remove
+ */
+
+/**
+ * xilinx_cdma_free_channel - Channel remove function
+ * @chan: Driver specific cdma channel
+ */
+static void xilinx_cdma_free_channel(struct xilinx_cdma_chan *chan)
+{
+ /* Disable Interrupts */
+ cdma_ctrl_clr(chan, XILINX_CDMA_CONTROL_OFFSET,
+ XILINX_CDMA_XR_IRQ_ALL_MASK);
+
+ if (chan->irq > 0)
+ free_irq(chan->irq, chan);
+
+ tasklet_kill(&chan->tasklet);
+
+ list_del(&chan->common.device_node);
+}
+
+/**
+ * xilinx_cdma_chan_probe - Per Channel Probing
+ * It get channel features from the device tree entry and
+ * initialize special channel handling routines
+ *
+ * @xdev: Driver specific device structure
+ * @node: Device node
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_cdma_chan_probe(struct xilinx_cdma_device *xdev,
+ struct device_node *node)
+{
+ struct xilinx_cdma_chan *chan;
+ bool has_dre;
+ u32 value, width;
+ int err;
+
+ /* Alloc channel */
+ chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_NOWAIT);
+ if (!chan)
+ return -ENOMEM;
+
+ chan->dev = xdev->dev;
+ chan->has_sg = xdev->has_sg;
+ chan->xdev = xdev;
+
+ spin_lock_init(&chan->lock);
+ INIT_LIST_HEAD(&chan->pending_list);
+ INIT_LIST_HEAD(&chan->done_list);
+
+ /* Retrieve the channel properties from the device tree */
+ has_dre = of_property_read_bool(node, "xlnx,include-dre");
+
+ err = of_property_read_u32(node, "xlnx,datawidth", &value);
+ if (err) {
+ dev_err(xdev->dev, "unable to read datawidth property");
+ return err;
+ }
+ width = value >> 3; /* convert bits to bytes */
+
+ /* If data width is greater than 8 bytes, DRE is not in hw */
+ if (width > 8)
+ has_dre = false;
+
+ if (!has_dre)
+ xdev->common.copy_align = fls(width - 1);
+
+ /* Request the interrupt */
+ chan->irq = irq_of_parse_and_map(node, 0);
+ err = request_irq(chan->irq, xilinx_cdma_irq_handler, IRQF_SHARED,
+ "xilinx-cdma-controller", chan);
+ if (err) {
+ dev_err(xdev->dev, "unable to request IRQ %d\n", chan->irq);
+ return err;
+ }
+
+ /* Initialize the tasklet */
+ tasklet_init(&chan->tasklet, xilinx_cdma_do_tasklet,
+ (unsigned long)chan);
+
+ /*
+ * Initialize the DMA channel and add it to the DMA engine channels
+ * list.
+ */
+ chan->common.device = &xdev->common;
+
+ list_add_tail(&chan->common.device_node, &xdev->common.channels);
+ xdev->chan = chan;
+
+ /* Initialize the channel */
+ err = xilinx_cdma_chan_reset(chan);
+ if (err) {
+ dev_err(xdev->dev, "Reset channel failed\n");
+ return err;
+ }
+
+ chan->idle = true;
+
+ return 0;
+}
+
+/**
+ * of_dma_xilinx_xlate - Translation function
+ * @dma_spec: Pointer to DMA specifier as found in the device tree
+ * @ofdma: Pointer to DMA controller data
+ *
+ * Return: DMA channel pointer on success and NULL on error
+ */
+static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct xilinx_cdma_device *xdev = ofdma->of_dma_data;
+
+ return dma_get_slave_channel(&xdev->chan->common);
+}
+
+/**
+ * xilinx_cdma_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xilinx_cdma_probe(struct platform_device *pdev)
+{
+ struct xilinx_cdma_device *xdev;
+ struct device_node *child, *node;
+ struct resource *res;
+ int ret;
+
+ xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ xdev->dev = &(pdev->dev);
+ INIT_LIST_HEAD(&xdev->common.channels);
+
+ node = pdev->dev.of_node;
+
+ /* Map the registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xdev->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(xdev->regs))
+ return PTR_ERR(xdev->regs);
+
+ /* Check if SG is enabled */
+ xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
+
+ dma_cap_set(DMA_MEMCPY, xdev->common.cap_mask);
+ xdev->common.device_prep_dma_memcpy = xilinx_cdma_prep_memcpy;
+ xdev->common.device_terminate_all = xilinx_cdma_terminate_all;
+ xdev->common.device_issue_pending = xilinx_cdma_issue_pending;
+ xdev->common.device_alloc_chan_resources =
+ xilinx_cdma_alloc_chan_resources;
+ xdev->common.device_free_chan_resources =
+ xilinx_cdma_free_chan_resources;
+ xdev->common.device_tx_status = xilinx_tx_status;
+ xdev->common.dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, xdev);
+
+ child = of_get_next_child(node, NULL);
+ if (!child) {
+ dev_err(&pdev->dev, "No channel found\n");
+ return PTR_ERR(child);
+ }
+
+ ret = xilinx_cdma_chan_probe(xdev, child);
+ if (ret) {
+ dev_err(&pdev->dev, "Probing channel failed\n");
+ goto free_chan_resources;
+ }
+
+ dma_async_device_register(&xdev->common);
+
+ ret = of_dma_controller_register(node, of_dma_xilinx_xlate, xdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to register DMA to DT\n");
+ dma_async_device_unregister(&xdev->common);
+ goto free_chan_resources;
+ }
+
+ dev_info(&pdev->dev, "Xilinx AXI CDMA Engine driver Probed!!\n");
+
+ return 0;
+
+free_chan_resources:
+ xilinx_cdma_free_channel(xdev->chan);
+
+ return ret;
+}
+
+/**
+ * xilinx_cdma_remove - Driver remove function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * Return: Always '0'
+ */
+static int xilinx_cdma_remove(struct platform_device *pdev)
+{
+ struct xilinx_cdma_device *xdev = platform_get_drvdata(pdev);
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&xdev->common);
+
+ xilinx_cdma_free_channel(xdev->chan);
+
+ return 0;
+}
+
+static const struct of_device_id xilinx_cdma_of_match[] = {
+ { .compatible = "xlnx,axi-cdma-1.00.a", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, xilinx_cdma_of_match);
+
+static struct platform_driver xilinx_cdma_driver = {
+ .driver = {
+ .name = "xilinx-cdma",
+ .owner = THIS_MODULE,
+ .of_match_table = xilinx_cdma_of_match,
+ },
+ .probe = xilinx_cdma_probe,
+ .remove = xilinx_cdma_remove,
+};
+
+module_platform_driver(xilinx_cdma_driver);
+
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Xilinx CDMA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/dma/xilinx_dma.h b/include/linux/dma/xilinx_dma.h
index 34b98f2..fb74ff7 100644
--- a/include/linux/dma/xilinx_dma.h
+++ b/include/linux/dma/xilinx_dma.h
@@ -41,7 +41,20 @@ struct xilinx_vdma_config {
int ext_fsync;
};

+/**
+ * struct xilinx_cdma_config - CDMA Configuration structure
+ * @coalesc: Interrupt coalescing threshold
+ * @delay: Delay counter
+ * @reset: Reset Channel
+ */
+struct xilinx_cdma_config {
+ int coalesc;
+ int delay;
+ int reset;
+};
+
int xilinx_vdma_channel_set_config(struct dma_chan *dchan,
struct xilinx_vdma_config *cfg);
-
+int xilinx_cdma_channel_set_config(struct dma_chan *dchan,
+ struct xilinx_cdma_config *cfg);
#endif
--
2.1.2


2015-05-22 10:31:00

by Paul Bolle

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

Again, just a nit: a license mismatch.

On Thu, 2015-05-21 at 22:37 +0530, Kedareswara rao Appana wrote:

> + * 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.

> +MODULE_LICENSE("GPL v2");

As I said in the message I sent a short while ago: here too I think that
either the comment at the top of this file or the ident used in the
MODULE_LICENSE() macro needs to change.

Thanks,


Paul Bolle

Subject: RE: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

Ping!

> -----Original Message-----
> From: Kedareswara rao Appana [mailto:[email protected]]
> Sent: Thursday, May 21, 2015 10:37 PM
> To: [email protected]; [email protected]; Michal Simek; Soren
> Brinkmann; Appana Durga Kedareswara Rao; Punnaiah Choudary Kalluri
> Cc: [email protected]; [email protected]; linux-
> [email protected]; Srikanth Thokala
> Subject: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access
> Engine driver support
>
> This is the driver for the AXI Central Direct Memory Access (AXI
> CDMA) core, which is a soft Xilinx IP core that provides high-bandwidth Direct
> Memory Access (DMA) between a memory-mapped source address and a
> memory-mapped destination address.
>
> This module works on Zynq (ARM Based SoC) and Microblaze platforms.
>
> Signed-off-by: Srikanth Thokala <[email protected]>
> Signed-off-by: Kedareswara rao Appana <[email protected]>
> ---
> This patch is rebased on the commit
> Merge tag 'nfs-for-4.1-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
>
> Changes in v4:
> - used GFP_NOWAIT instead of GFP_KERNEL during the desc allocation
> - Modified spin_lock handling moved the spin_lock to the appropriate
> functions
> - device_control api is removed and updated driver as per newer APi's.
> Changes in v3:
> - Check for CDMA idle condition before changing the configuration.
> - Modified the xilinx_dma.h header file location to the
> include/linux/dma/xilinx_dma.h
> Changes in v2:
> - Rebased on 3.16-rc7.
>
> drivers/dma/Kconfig | 12 +
> drivers/dma/xilinx/Makefile | 1 +
> drivers/dma/xilinx/xilinx_cdma.c | 987
> +++++++++++++++++++++++++++++++++++++++
> include/linux/dma/xilinx_dma.h | 15 +-
> 4 files changed, 1014 insertions(+), 1 deletion(-) create mode 100644
> drivers/dma/xilinx/xilinx_cdma.c
>
> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index
> bda2cb0..c42cf24 100644
> --- a/drivers/dma/Kconfig
> +++ b/drivers/dma/Kconfig
> @@ -492,4 +492,16 @@ config QCOM_BAM_DMA
> Enable support for the QCOM BAM DMA controller. This controller
> provides DMA capabilities for a variety of on-chip devices.
>
> +config XILINX_CDMA
> + tristate "Xilinx AXI CDMA Engine"
> + depends on (ARCH_ZYNQ || MICROBLAZE)
> + select DMA_ENGINE
> + help
> + Enable support for Xilinx AXI CDMA Soft IP.
> +
> + The AXI CDMA is a soft IP which provides high-bandwidth
> + Direct Memory Access (DMA) between a memory-mapped source
> + address and a memory-mapped destination address using the
> + AXI4 protocol.
> +
> endif
> diff --git a/drivers/dma/xilinx/Makefile b/drivers/dma/xilinx/Makefile index
> 3c4e9f2..f909d34 100644
> --- a/drivers/dma/xilinx/Makefile
> +++ b/drivers/dma/xilinx/Makefile
> @@ -1 +1,2 @@
> obj-$(CONFIG_XILINX_VDMA) += xilinx_vdma.o
> +obj-$(CONFIG_XILINX_VDMA) += xilinx_cdma.o
> diff --git a/drivers/dma/xilinx/xilinx_cdma.c
> b/drivers/dma/xilinx/xilinx_cdma.c
> new file mode 100644
> index 0000000..eda443a
> --- /dev/null
> +++ b/drivers/dma/xilinx/xilinx_cdma.c
> @@ -0,0 +1,987 @@
> +/*
> + * DMA driver for Xilinx Central DMA Engine
> + *
> + * Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved.
> + *
> + * Based on the Freescale DMA driver.
> + *
> + * Description:
> + * The AXI CDMA, is a soft IP, which provides high-bandwidth Direct
> +Memory
> + * Access (DMA) between a memory-mapped source address and a
> +memory-mapped
> + * destination address.
> + *
> + * 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 <linux/bitops.h>
> +#include <linux/dmapool.h>
> +#include <linux/dma/xilinx_dma.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_dma.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/slab.h>
> +
> +#include "../dmaengine.h"
> +
> +/* Register Offsets */
> +#define XILINX_CDMA_CONTROL_OFFSET 0x00
> +#define XILINX_CDMA_STATUS_OFFSET 0x04
> +#define XILINX_CDMA_CDESC_OFFSET 0x08
> +#define XILINX_CDMA_TDESC_OFFSET 0x10
> +#define XILINX_CDMA_SRCADDR_OFFSET 0x18
> +#define XILINX_CDMA_DSTADDR_OFFSET 0x20
> +#define XILINX_CDMA_BTT_OFFSET 0x28
> +
> +/* General register bits definitions */
> +#define XILINX_CDMA_CR_RESET BIT(2)
> +#define XILINX_CDMA_CR_SGMODE BIT(3)
> +
> +#define XILINX_CDMA_SR_IDLE BIT(1)
> +
> +#define XILINX_CDMA_XR_IRQ_IOC_MASK BIT(12)
> +#define XILINX_CDMA_XR_IRQ_DELAY_MASK BIT(13) #define
> +XILINX_CDMA_XR_IRQ_ERROR_MASK BIT(14)
> +#define XILINX_CDMA_XR_IRQ_ALL_MASK GENMASK(14, 12)
> +
> +#define XILINX_CDMA_XR_DELAY_MASK GENMASK(31, 24)
> +#define XILINX_CDMA_XR_COALESCE_MASK GENMASK(23, 16)
> +
> +#define XILINX_CDMA_DELAY_MAX GENMASK(7, 0)
> +#define XILINX_CDMA_DELAY_SHIFT 24
> +
> +#define XILINX_CDMA_COALESCE_MAX GENMASK(7, 0)
> +#define XILINX_CDMA_COALESCE_SHIFT 16
> +
> +/* Delay loop counter to prevent hardware failure */
> +#define XILINX_CDMA_RESET_LOOP 1000000
> +
> +/* Maximum transfer length */
> +#define XILINX_CDMA_MAX_TRANS_LEN GENMASK(22, 0)
> +
> +/**
> + * struct xilinx_cdma_desc_hw - Hardware Descriptor
> + * @next_desc: Next Descriptor Pointer @0x00
> + * @pad1: Reserved @0x04
> + * @src_addr: Source address @0x08
> + * @pad2: Reserved @0x0C
> + * @dest_addr: Destination address @0x10
> + * @pad3: Reserved @0x14
> + * @control: Control field @0x18
> + * @status: Status field @0x1C
> + */
> +struct xilinx_cdma_desc_hw {
> + u32 next_desc;
> + u32 pad1;
> + u32 src_addr;
> + u32 pad2;
> + u32 dest_addr;
> + u32 pad3;
> + u32 control;
> + u32 status;
> +} __aligned(64);
> +
> +/**
> + * struct xilinx_cdma_tx_segment - Descriptor segment
> + * @hw: Hardware descriptor
> + * @node: Node in the descriptor segments list
> + * @phys: Physical address of segment
> + */
> +struct xilinx_cdma_tx_segment {
> + struct xilinx_cdma_desc_hw hw;
> + struct list_head node;
> + dma_addr_t phys;
> +} __aligned(64);
> +
> +/**
> + * struct xilinx_cdma_tx_descriptor - Per Transaction structure
> + * @async_tx: Async transaction descriptor
> + * @segments: TX segments list
> + * @node: Node in the channel descriptors list */ struct
> +xilinx_cdma_tx_descriptor {
> + struct dma_async_tx_descriptor async_tx;
> + struct list_head segments;
> + struct list_head node;
> +};
> +
> +/**
> + * struct xilinx_cdma_chan - Driver specific cdma channel structure
> + * @xdev: Driver specific device structure
> + * @lock: Descriptor operation lock
> + * @done_list: Complete descriptors
> + * @pending_list: Descriptors waiting
> + * @active_desc: Active descriptor
> + * @common: DMA common channel
> + * @desc_pool: Descriptors pool
> + * @dev: The dma device
> + * @irq: Channel IRQ
> + * @has_sg: Support scatter transfers
> + * @err: Channel has errors
> + * @idle: Channel status
> + * @tasklet: Cleanup work after irq
> + */
> +struct xilinx_cdma_chan {
> + struct xilinx_cdma_device *xdev;
> + spinlock_t lock;
> + struct list_head done_list;
> + struct list_head pending_list;
> + struct xilinx_cdma_tx_descriptor *active_desc;
> + struct dma_chan common;
> + struct dma_pool *desc_pool;
> + struct device *dev;
> + int irq;
> + bool has_sg;
> + int err;
> + bool idle;
> + struct tasklet_struct tasklet;
> +};
> +
> +/**
> + * struct xilinx_cdma_device - CDMA device structure
> + * @regs: I/O mapped base address
> + * @dev: Device Structure
> + * @common: DMA device structure
> + * @chan: Driver specific cdma channel
> + * @has_sg: Specifies whether Scatter-Gather is present or not */
> +struct xilinx_cdma_device {
> + void __iomem *regs;
> + struct device *dev;
> + struct dma_device common;
> + struct xilinx_cdma_chan *chan;
> + bool has_sg;
> +};
> +
> +/* Macros */
> +#define to_xilinx_chan(chan) \
> + container_of(chan, struct xilinx_cdma_chan, common) #define
> +to_cdma_tx_descriptor(tx) \
> + container_of(tx, struct xilinx_cdma_tx_descriptor, async_tx)
> +
> +/* IO accessors */
> +static inline void cdma_write(struct xilinx_cdma_chan *chan, u32 reg,
> +u32 val) {
> + writel(val, chan->xdev->regs + reg);
> +}
> +
> +static inline u32 cdma_read(struct xilinx_cdma_chan *chan, u32 reg) {
> + return readl(chan->xdev->regs + reg);
> +}
> +
> +static inline void cdma_ctrl_clr(struct xilinx_cdma_chan *chan, u32 reg,
> + u32 clr)
> +{
> + cdma_write(chan, reg, cdma_read(chan, reg) & ~clr); }
> +
> +static inline void cdma_ctrl_set(struct xilinx_cdma_chan *chan, u32 reg,
> + u32 set)
> +{
> + cdma_write(chan, reg, cdma_read(chan, reg) | set); }
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * Descriptors and segments alloc and free */
> +
> +/**
> + * xilinx_cdma_alloc_tx_segment - Allocate transaction segment
> + * @chan: Driver specific cdma channel
> + *
> + * Return: The allocated segment on success and NULL on failure.
> + */
> +static struct xilinx_cdma_tx_segment *
> +xilinx_cdma_alloc_tx_segment(struct xilinx_cdma_chan *chan) {
> + struct xilinx_cdma_tx_segment *segment;
> + dma_addr_t phys;
> +
> + segment = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &phys);
> + if (!segment)
> + return NULL;
> +
> + memset(segment, 0, sizeof(*segment));
> + segment->phys = phys;
> +
> + return segment;
> +}
> +
> +/**
> + * xilinx_cdma_free_tx_segment - Free transaction segment
> + * @chan: Driver specific cdma channel
> + * @segment: cdma transaction segment
> + */
> +static void xilinx_cdma_free_tx_segment(struct xilinx_cdma_chan *chan,
> + struct xilinx_cdma_tx_segment
> *segment) {
> + dma_pool_free(chan->desc_pool, segment, segment->phys); }
> +
> +/**
> + * xilinx_cdma_tx_descriptor - Allocate transaction descriptor
> + * @chan: Driver specific cdma channel
> + *
> + * Return: The allocated descriptor on success and NULL on failure.
> + */
> +static struct xilinx_cdma_tx_descriptor *
> +xilinx_cdma_alloc_tx_descriptor(struct xilinx_cdma_chan *chan) {
> + struct xilinx_cdma_tx_descriptor *desc;
> +
> + desc = kzalloc(sizeof(*desc), GFP_KERNEL);
> + if (!desc)
> + return NULL;
> +
> + INIT_LIST_HEAD(&desc->segments);
> +
> + return desc;
> +}
> +
> +/**
> + * xilinx_cdma_free_tx_descriptor - Free transaction descriptor
> + * @chan: Driver specific cdma channel
> + * @desc: cdma transaction descriptor
> + */
> +static void
> +xilinx_cdma_free_tx_descriptor(struct xilinx_cdma_chan *chan,
> + struct xilinx_cdma_tx_descriptor *desc) {
> + struct xilinx_cdma_tx_segment *segment, *next;
> +
> + if (!desc)
> + return;
> +
> + list_for_each_entry_safe(segment, next, &desc->segments, node) {
> + list_del(&segment->node);
> + xilinx_cdma_free_tx_segment(chan, segment);
> + }
> +
> + kfree(desc);
> +}
> +
> +/**
> + * xilinx_cdma_alloc_chan_resources - Allocate channel resources
> + * @dchan: DMA channel
> + *
> + * Return: '0' on success and failure value on error */ static int
> +xilinx_cdma_alloc_chan_resources(struct dma_chan *dchan) {
> + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
> +
> + /* Has this channel already been allocated? */
> + if (chan->desc_pool)
> + return 0;
> +
> + /*
> + * We need the descriptor to be aligned to 64bytes
> + * for meeting Xilinx DMA specification requirement.
> + */
> + chan->desc_pool = dma_pool_create("xilinx_cdma_desc_pool",
> + chan->dev,
> + sizeof(struct xilinx_cdma_tx_segment),
> + __alignof__(struct
> xilinx_cdma_tx_segment), 0);
> + if (!chan->desc_pool) {
> + dev_err(chan->dev,
> + "unable to allocate channel descriptor pool\n");
> + return -ENOMEM;
> + }
> +
> + dma_cookie_init(dchan);
> + return 0;
> +}
> +
> +/**
> + * xilinx_cdma_free_desc_list - Free descriptors list
> + * @chan: Driver specific cdma channel
> + * @list: List to parse and delete the descriptor */ static void
> +xilinx_cdma_free_desc_list(struct xilinx_cdma_chan *chan,
> + struct list_head *list)
> +{
> + struct xilinx_cdma_tx_descriptor *desc, *next;
> +
> + list_for_each_entry_safe(desc, next, list, node) {
> + list_del(&desc->node);
> + xilinx_cdma_free_tx_descriptor(chan, desc);
> + }
> +}
> +
> +/**
> + * xilinx_cdma_free_chan_resources - Free channel resources
> + * @dchan: DMA channel
> + */
> +static void xilinx_cdma_free_chan_resources(struct dma_chan *dchan) {
> + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&chan->lock, flags);
> + xilinx_cdma_free_desc_list(chan, &chan->done_list);
> + xilinx_cdma_free_desc_list(chan, &chan->pending_list);
> + spin_unlock_irqrestore(&chan->lock, flags);
> +
> + dma_pool_destroy(chan->desc_pool);
> + chan->desc_pool = NULL;
> +}
> +
> +/**
> + * xilinx_cdma_chan_desc_cleanup - Clean channel descriptors
> + * @chan: Driver specific cdma channel
> + */
> +static void xilinx_cdma_chan_desc_cleanup(struct xilinx_cdma_chan
> +*chan) {
> + struct xilinx_cdma_tx_descriptor *desc, *next;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&chan->lock, flags);
> +
> + list_for_each_entry_safe(desc, next, &chan->done_list, node) {
> + dma_async_tx_callback callback;
> + void *callback_param;
> +
> + /* Remove from the list of running transactions */
> + list_del(&desc->node);
> +
> + /* Run the link descriptor callback function */
> + callback = desc->async_tx.callback;
> + callback_param = desc->async_tx.callback_param;
> + if (callback) {
> + spin_unlock_irqrestore(&chan->lock, flags);
> + callback(callback_param);
> + spin_lock_irqsave(&chan->lock, flags);
> + }
> +
> + /* Run any dependencies, then free the descriptor */
> + dma_run_dependencies(&desc->async_tx);
> + xilinx_cdma_free_tx_descriptor(chan, desc);
> + }
> +
> + spin_unlock_irqrestore(&chan->lock, flags); }
> +
> +/**
> + * xilinx_cdma_tx_status - Get CDMA transaction status
> + * @dchan: DMA channel
> + * @cookie: Transaction identifier
> + * @txstate: Transaction state
> + *
> + * Return: DMA transaction status
> + */
> +static enum dma_status xilinx_tx_status(struct dma_chan *dchan,
> + dma_cookie_t cookie,
> + struct dma_tx_state *txstate)
> +{
> + return dma_cookie_status(dchan, cookie, txstate); }
> +
> +/**
> + * xilinx_cdma_is_idle - Check if cdma channel is idle
> + * @chan: Driver specific cdma channel
> + *
> + * Return: 'true' if idle, 'false' if not.
> + */
> +static bool cdma_is_idle(struct xilinx_cdma_chan *chan) {
> + return cdma_read(chan, XILINX_CDMA_STATUS_OFFSET) &
> +XILINX_CDMA_SR_IDLE; }
> +
> +/**
> + * xilinx_cdma_start_transfer - Starts cdma transfer
> + * @chan: Driver specific channel struct pointer */ static void
> +xilinx_cdma_start_transfer(struct xilinx_cdma_chan *chan) {
> + struct xilinx_cdma_tx_descriptor *desc;
> + struct xilinx_cdma_tx_segment *head, *tail;
> +
> + if (chan->err)
> + return;
> +
> + if (list_empty(&chan->pending_list))
> + return;
> +
> + if (!chan->idle)
> + return;
> +
> + /* If hardware is busy, cannot submit */
> + if (chan->has_sg && !cdma_is_idle(chan)) {
> + tail = list_entry(desc->segments.prev,
> + struct xilinx_cdma_tx_segment, node);
> + cdma_write(chan, XILINX_CDMA_TDESC_OFFSET, tail-
> >phys);
> + goto out_free_desc;
> + }
> +
> + desc = list_first_entry(&chan->pending_list,
> + struct xilinx_cdma_tx_descriptor, node);
> +
> + if (chan->has_sg) {
> + head = list_first_entry(&desc->segments,
> + struct xilinx_cdma_tx_segment,
> node);
> + tail = list_entry(desc->segments.prev,
> + struct xilinx_cdma_tx_segment, node);
> +
> + cdma_write(chan, XILINX_CDMA_CDESC_OFFSET, head-
> >phys);
> +
> + /* Update tail ptr register which will start the transfer */
> + cdma_write(chan, XILINX_CDMA_TDESC_OFFSET, tail-
> >phys);
> + } else {
> + /* In simple mode */
> + struct xilinx_cdma_tx_segment *segment;
> + struct xilinx_cdma_desc_hw *hw;
> +
> + segment = list_first_entry(&desc->segments,
> + struct xilinx_cdma_tx_segment,
> + node);
> +
> + hw = &segment->hw;
> +
> + cdma_write(chan, XILINX_CDMA_SRCADDR_OFFSET, hw-
> >src_addr);
> + cdma_write(chan, XILINX_CDMA_DSTADDR_OFFSET, hw-
> >dest_addr);
> +
> + /* Start the transfer */
> + cdma_write(chan, XILINX_CDMA_BTT_OFFSET,
> + hw->control &
> XILINX_CDMA_MAX_TRANS_LEN);
> + }
> +
> +out_free_desc:
> + list_del(&desc->node);
> + chan->idle = false;
> + chan->active_desc = desc;
> +}
> +
> +/**
> + * xilinx_cdma_issue_pending - Issue pending transactions
> + * @dchan: DMA channel
> + */
> +static void xilinx_cdma_issue_pending(struct dma_chan *dchan) {
> + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&chan->lock, flags);
> + xilinx_cdma_start_transfer(chan);
> + spin_unlock_irqrestore(&chan->lock, flags); }
> +
> +/**
> + * xilinx_cdma_complete_descriptor - Mark the active descriptor as
> +complete
> + * @chan : xilinx DMA channel
> + */
> +static void xilinx_cdma_complete_descriptor(struct xilinx_cdma_chan
> +*chan) {
> + struct xilinx_cdma_tx_descriptor *desc;
> +
> + desc = chan->active_desc;
> + if (!desc) {
> + dev_dbg(chan->dev, "no running descriptors\n");
> + return;
> + }
> +
> + dma_cookie_complete(&desc->async_tx);
> + list_add_tail(&desc->node, &chan->done_list);
> +
> + chan->active_desc = NULL;
> +}
> +
> +/**
> + * xilinx_cdma_chan_reset - Reset CDMA channel
> + * @chan: Driver specific CDMA channel
> + *
> + * Return: '0' on success and failure value on error */ static int
> +xilinx_cdma_chan_reset(struct xilinx_cdma_chan *chan) {
> + int loop = XILINX_CDMA_RESET_LOOP;
> + u32 tmp;
> +
> + cdma_ctrl_set(chan, XILINX_CDMA_CONTROL_OFFSET,
> + XILINX_CDMA_CR_RESET);
> +
> + tmp = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) &
> + XILINX_CDMA_CR_RESET;
> +
> + /* Wait for the hardware to finish reset */
> + do {
> + tmp = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET) &
> + XILINX_CDMA_CR_RESET;
> + } while (loop-- && tmp);
> +
> + if (!loop) {
> + dev_err(chan->dev, "reset timeout, cr %x, sr %x\n",
> + cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET),
> + cdma_read(chan, XILINX_CDMA_STATUS_OFFSET));
> + return -EBUSY;
> + }
> +
> + /* Enable interrupts */
> + cdma_ctrl_set(chan, XILINX_CDMA_CONTROL_OFFSET,
> + XILINX_CDMA_XR_IRQ_ALL_MASK);
> +
> + /* Enable SG Mode */
> + if (chan->has_sg)
> + cdma_ctrl_set(chan, XILINX_CDMA_CONTROL_OFFSET,
> + XILINX_CDMA_CR_SGMODE);
> + return 0;
> +}
> +
> +/**
> + * xilinx_cdma_irq_handler - CDMA Interrupt handler
> + * @irq: IRQ number
> + * @data: Pointer to the Xilinx CDMA channel structure
> + *
> + * Return: IRQ_HANDLED/IRQ_NONE
> + */
> +static irqreturn_t xilinx_cdma_irq_handler(int irq, void *data) {
> + struct xilinx_cdma_chan *chan = data;
> + u32 status;
> +
> + status = cdma_read(chan, XILINX_CDMA_STATUS_OFFSET);
> + if (!(status & XILINX_CDMA_XR_IRQ_ALL_MASK))
> + return IRQ_NONE;
> +
> + /* Ack the interrupts */
> + cdma_write(chan, XILINX_CDMA_STATUS_OFFSET,
> + XILINX_CDMA_XR_IRQ_ALL_MASK);
> +
> + if (status & XILINX_CDMA_XR_IRQ_ERROR_MASK) {
> + dev_err(chan->dev,
> + "Channel %x has errors %x, cdr %x tdr %x\n",
> + (u32)chan,
> + (u32)cdma_read(chan,
> XILINX_CDMA_STATUS_OFFSET),
> + (u32)cdma_read(chan,
> XILINX_CDMA_CDESC_OFFSET),
> + (u32)cdma_read(chan,
> XILINX_CDMA_TDESC_OFFSET));
> + chan->err = true;
> + }
> +
> + /*
> + * Device takes too long to do the transfer when user requires
> + * responsiveness
> + */
> + if (status & XILINX_CDMA_XR_IRQ_DELAY_MASK)
> + dev_dbg(chan->dev, "Inter-packet latency too long\n");
> +
> + if (status & XILINX_CDMA_XR_IRQ_IOC_MASK) {
> + spin_lock(&chan->lock);
> + xilinx_cdma_complete_descriptor(chan);
> + chan->idle = true;
> + xilinx_cdma_start_transfer(chan);
> + spin_unlock(&chan->lock);
> + }
> +
> + tasklet_schedule(&chan->tasklet);
> + return IRQ_HANDLED;
> +}
> +
> +/**
> + * xilinx_cdma_do_tasklet - Schedule completion tasklet
> + * @data: Pointer to the Xilinx cdma channel structure */ static void
> +xilinx_cdma_do_tasklet(unsigned long data) {
> + struct xilinx_cdma_chan *chan = (struct xilinx_cdma_chan *)data;
> +
> + xilinx_cdma_chan_desc_cleanup(chan);
> +}
> +
> +/**
> + * xilinx_cdma_tx_submit - Submit DMA transaction
> + * @tx: Async transaction descriptor
> + *
> + * Return: cookie value on success and failure value on error */
> +static dma_cookie_t xilinx_cdma_tx_submit(struct
> +dma_async_tx_descriptor *tx) {
> + struct xilinx_cdma_chan *chan = to_xilinx_chan(tx->chan);
> + struct xilinx_cdma_tx_descriptor *desc =
> to_cdma_tx_descriptor(tx);
> + dma_cookie_t cookie;
> + unsigned long flags;
> + int err;
> +
> + if (chan->err) {
> + /*
> + * If reset fails, need to hard reset the system.
> + * Channel is no longer functional
> + */
> + err = xilinx_cdma_chan_reset(chan);
> + if (err < 0)
> + return err;
> + }
> +
> + spin_lock_irqsave(&chan->lock, flags);
> +
> + cookie = dma_cookie_assign(tx);
> +
> + /* Append the transaction to the pending transactions queue. */
> + list_add_tail(&desc->node, &chan->pending_list);
> +
> + spin_unlock_irqrestore(&chan->lock, flags);
> +
> + return cookie;
> +}
> +
> +/**
> + * xilinx_cdma_prep_memcpy - prepare descriptors for a memcpy
> +transaction
> + * @dchan: DMA channel
> + * @dma_dst: destination address
> + * @dma_src: source address
> + * @len: transfer length
> + * @flags: transfer ack flags
> + *
> + * Return: Async transaction descriptor on success and NULL on failure
> +*/ static struct dma_async_tx_descriptor *
> +xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t
> dma_dst,
> + dma_addr_t dma_src, size_t len, unsigned long flags)
> {
> + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
> + struct xilinx_cdma_desc_hw *hw;
> + struct xilinx_cdma_tx_descriptor *desc;
> + struct xilinx_cdma_tx_segment *segment, *prev;
> +
> + if (!len || len > XILINX_CDMA_MAX_TRANS_LEN)
> + return NULL;
> +
> + desc = xilinx_cdma_alloc_tx_descriptor(chan);
> + if (!desc)
> + return NULL;
> +
> + dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
> + desc->async_tx.tx_submit = xilinx_cdma_tx_submit;
> + async_tx_ack(&desc->async_tx);
> +
> + /* Allocate the link descriptor from DMA pool */
> + segment = xilinx_cdma_alloc_tx_segment(chan);
> + if (!segment)
> + goto error;
> +
> + hw = &segment->hw;
> + hw->control = len;
> + hw->src_addr = dma_src;
> + hw->dest_addr = dma_dst;
> +
> + /* Fill the previous next descriptor with current */
> + prev = list_last_entry(&desc->segments,
> + struct xilinx_cdma_tx_segment, node);
> + prev->hw.next_desc = segment->phys;
> +
> + /* Insert the segment into the descriptor segments list. */
> + list_add_tail(&segment->node, &desc->segments);
> +
> + prev = segment;
> +
> + /* Link the last hardware descriptor with the first. */
> + segment = list_first_entry(&desc->segments,
> + struct xilinx_cdma_tx_segment, node);
> + prev->hw.next_desc = segment->phys;
> +
> + return &desc->async_tx;
> +
> +error:
> + xilinx_cdma_free_tx_descriptor(chan, desc);
> + return NULL;
> +}
> +
> +/**
> + * xilinx_cdma_terminate_all - Free the descriptors
> + * @dchan: DMA Channel pointer
> + *
> + * Return: '0' always
> + */
> +static int xilinx_cdma_terminate_all(struct dma_chan *dchan) {
> + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&chan->lock, flags);
> +
> + /* Reset the channel */
> + xilinx_cdma_chan_reset(chan);
> +
> + /* Remove and free all of the descriptors in the lists */
> + xilinx_cdma_free_desc_list(chan, &chan->pending_list);
> + xilinx_cdma_free_desc_list(chan, &chan->done_list);
> +
> + spin_unlock_irqrestore(&chan->lock, flags);
> +
> + return 0;
> +}
> +
> +/**
> + * xilinx_cdma_channel_set_config - Configure cdma channel
> + * @dchan: DMA channel
> + * @cfg: cdma device configuration pointer
> + *
> + * Return: '0' on success and failure value on error */ int
> +xilinx_cdma_channel_set_config(struct dma_chan *dchan,
> + struct xilinx_cdma_config *cfg)
> +{
> + struct xilinx_cdma_chan *chan = to_xilinx_chan(dchan);
> + u32 reg = cdma_read(chan, XILINX_CDMA_CONTROL_OFFSET);
> +
> + if (!cdma_is_idle(chan))
> + return -EBUSY;
> +
> + if (cfg->reset)
> + return xilinx_cdma_chan_reset(chan);
> +
> + if (cfg->coalesc <= XILINX_CDMA_COALESCE_MAX) {
> + reg &= ~XILINX_CDMA_XR_COALESCE_MASK;
> + reg |= cfg->coalesc << XILINX_CDMA_COALESCE_SHIFT;
> + }
> +
> + if (cfg->delay <= XILINX_CDMA_DELAY_MAX) {
> + reg &= ~XILINX_CDMA_XR_DELAY_MASK;
> + reg |= cfg->delay << XILINX_CDMA_DELAY_SHIFT;
> + }
> +
> + cdma_write(chan, XILINX_CDMA_CONTROL_OFFSET, reg);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(xilinx_cdma_channel_set_config);
> +
> +/*
> +-----------------------------------------------------------------------
> +------
> + * Probe and remove
> + */
> +
> +/**
> + * xilinx_cdma_free_channel - Channel remove function
> + * @chan: Driver specific cdma channel
> + */
> +static void xilinx_cdma_free_channel(struct xilinx_cdma_chan *chan) {
> + /* Disable Interrupts */
> + cdma_ctrl_clr(chan, XILINX_CDMA_CONTROL_OFFSET,
> + XILINX_CDMA_XR_IRQ_ALL_MASK);
> +
> + if (chan->irq > 0)
> + free_irq(chan->irq, chan);
> +
> + tasklet_kill(&chan->tasklet);
> +
> + list_del(&chan->common.device_node);
> +}
> +
> +/**
> + * xilinx_cdma_chan_probe - Per Channel Probing
> + * It get channel features from the device tree entry and
> + * initialize special channel handling routines
> + *
> + * @xdev: Driver specific device structure
> + * @node: Device node
> + *
> + * Return: '0' on success and failure value on error */ static int
> +xilinx_cdma_chan_probe(struct xilinx_cdma_device *xdev,
> + struct device_node *node)
> +{
> + struct xilinx_cdma_chan *chan;
> + bool has_dre;
> + u32 value, width;
> + int err;
> +
> + /* Alloc channel */
> + chan = devm_kzalloc(xdev->dev, sizeof(*chan), GFP_NOWAIT);
> + if (!chan)
> + return -ENOMEM;
> +
> + chan->dev = xdev->dev;
> + chan->has_sg = xdev->has_sg;
> + chan->xdev = xdev;
> +
> + spin_lock_init(&chan->lock);
> + INIT_LIST_HEAD(&chan->pending_list);
> + INIT_LIST_HEAD(&chan->done_list);
> +
> + /* Retrieve the channel properties from the device tree */
> + has_dre = of_property_read_bool(node, "xlnx,include-dre");
> +
> + err = of_property_read_u32(node, "xlnx,datawidth", &value);
> + if (err) {
> + dev_err(xdev->dev, "unable to read datawidth property");
> + return err;
> + }
> + width = value >> 3; /* convert bits to bytes */
> +
> + /* If data width is greater than 8 bytes, DRE is not in hw */
> + if (width > 8)
> + has_dre = false;
> +
> + if (!has_dre)
> + xdev->common.copy_align = fls(width - 1);
> +
> + /* Request the interrupt */
> + chan->irq = irq_of_parse_and_map(node, 0);
> + err = request_irq(chan->irq, xilinx_cdma_irq_handler, IRQF_SHARED,
> + "xilinx-cdma-controller", chan);
> + if (err) {
> + dev_err(xdev->dev, "unable to request IRQ %d\n", chan-
> >irq);
> + return err;
> + }
> +
> + /* Initialize the tasklet */
> + tasklet_init(&chan->tasklet, xilinx_cdma_do_tasklet,
> + (unsigned long)chan);
> +
> + /*
> + * Initialize the DMA channel and add it to the DMA engine channels
> + * list.
> + */
> + chan->common.device = &xdev->common;
> +
> + list_add_tail(&chan->common.device_node, &xdev-
> >common.channels);
> + xdev->chan = chan;
> +
> + /* Initialize the channel */
> + err = xilinx_cdma_chan_reset(chan);
> + if (err) {
> + dev_err(xdev->dev, "Reset channel failed\n");
> + return err;
> + }
> +
> + chan->idle = true;
> +
> + return 0;
> +}
> +
> +/**
> + * of_dma_xilinx_xlate - Translation function
> + * @dma_spec: Pointer to DMA specifier as found in the device tree
> + * @ofdma: Pointer to DMA controller data
> + *
> + * Return: DMA channel pointer on success and NULL on error */ static
> +struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args
> *dma_spec,
> + struct of_dma *ofdma)
> +{
> + struct xilinx_cdma_device *xdev = ofdma->of_dma_data;
> +
> + return dma_get_slave_channel(&xdev->chan->common);
> +}
> +
> +/**
> + * xilinx_cdma_probe - Driver probe function
> + * @pdev: Pointer to the platform_device structure
> + *
> + * Return: '0' on success and failure value on error */ static int
> +xilinx_cdma_probe(struct platform_device *pdev) {
> + struct xilinx_cdma_device *xdev;
> + struct device_node *child, *node;
> + struct resource *res;
> + int ret;
> +
> + xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
> + if (!xdev)
> + return -ENOMEM;
> +
> + xdev->dev = &(pdev->dev);
> + INIT_LIST_HEAD(&xdev->common.channels);
> +
> + node = pdev->dev.of_node;
> +
> + /* Map the registers */
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + xdev->regs = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(xdev->regs))
> + return PTR_ERR(xdev->regs);
> +
> + /* Check if SG is enabled */
> + xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
> +
> + dma_cap_set(DMA_MEMCPY, xdev->common.cap_mask);
> + xdev->common.device_prep_dma_memcpy =
> xilinx_cdma_prep_memcpy;
> + xdev->common.device_terminate_all = xilinx_cdma_terminate_all;
> + xdev->common.device_issue_pending =
> xilinx_cdma_issue_pending;
> + xdev->common.device_alloc_chan_resources =
> + xilinx_cdma_alloc_chan_resources;
> + xdev->common.device_free_chan_resources =
> + xilinx_cdma_free_chan_resources;
> + xdev->common.device_tx_status = xilinx_tx_status;
> + xdev->common.dev = &pdev->dev;
> +
> + platform_set_drvdata(pdev, xdev);
> +
> + child = of_get_next_child(node, NULL);
> + if (!child) {
> + dev_err(&pdev->dev, "No channel found\n");
> + return PTR_ERR(child);
> + }
> +
> + ret = xilinx_cdma_chan_probe(xdev, child);
> + if (ret) {
> + dev_err(&pdev->dev, "Probing channel failed\n");
> + goto free_chan_resources;
> + }
> +
> + dma_async_device_register(&xdev->common);
> +
> + ret = of_dma_controller_register(node, of_dma_xilinx_xlate, xdev);
> + if (ret) {
> + dev_err(&pdev->dev, "Unable to register DMA to DT\n");
> + dma_async_device_unregister(&xdev->common);
> + goto free_chan_resources;
> + }
> +
> + dev_info(&pdev->dev, "Xilinx AXI CDMA Engine driver Probed!!\n");
> +
> + return 0;
> +
> +free_chan_resources:
> + xilinx_cdma_free_channel(xdev->chan);
> +
> + return ret;
> +}
> +
> +/**
> + * xilinx_cdma_remove - Driver remove function
> + * @pdev: Pointer to the platform_device structure
> + *
> + * Return: Always '0'
> + */
> +static int xilinx_cdma_remove(struct platform_device *pdev) {
> + struct xilinx_cdma_device *xdev = platform_get_drvdata(pdev);
> +
> + of_dma_controller_free(pdev->dev.of_node);
> + dma_async_device_unregister(&xdev->common);
> +
> + xilinx_cdma_free_channel(xdev->chan);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id xilinx_cdma_of_match[] = {
> + { .compatible = "xlnx,axi-cdma-1.00.a", },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, xilinx_cdma_of_match);
> +
> +static struct platform_driver xilinx_cdma_driver = {
> + .driver = {
> + .name = "xilinx-cdma",
> + .owner = THIS_MODULE,
> + .of_match_table = xilinx_cdma_of_match,
> + },
> + .probe = xilinx_cdma_probe,
> + .remove = xilinx_cdma_remove,
> +};
> +
> +module_platform_driver(xilinx_cdma_driver);
> +
> +MODULE_AUTHOR("Xilinx, Inc.");
> +MODULE_DESCRIPTION("Xilinx CDMA driver"); MODULE_LICENSE("GPL
> v2");
> diff --git a/include/linux/dma/xilinx_dma.h
> b/include/linux/dma/xilinx_dma.h index 34b98f2..fb74ff7 100644
> --- a/include/linux/dma/xilinx_dma.h
> +++ b/include/linux/dma/xilinx_dma.h
> @@ -41,7 +41,20 @@ struct xilinx_vdma_config {
> int ext_fsync;
> };
>
> +/**
> + * struct xilinx_cdma_config - CDMA Configuration structure
> + * @coalesc: Interrupt coalescing threshold
> + * @delay: Delay counter
> + * @reset: Reset Channel
> + */
> +struct xilinx_cdma_config {
> + int coalesc;
> + int delay;
> + int reset;
> +};
> +
> int xilinx_vdma_channel_set_config(struct dma_chan *dchan,
> struct xilinx_vdma_config *cfg);
> -
> +int xilinx_cdma_channel_set_config(struct dma_chan *dchan,
> + struct xilinx_cdma_config *cfg);
> #endif
> --
> 2.1.2



This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

Subject: RE: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

Hi Paul,


> -----Original Message-----
> From: Paul Bolle [mailto:[email protected]]
> Sent: Friday, May 22, 2015 4:01 PM
> To: Appana Durga Kedareswara Rao
> Cc: [email protected]; [email protected]; Michal Simek; Soren
> Brinkmann; Appana Durga Kedareswara Rao; Punnaiah Choudary Kalluri;
> [email protected]; [email protected]; linux-
> [email protected]; Srikanth Thokala
> Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory
> Access Engine driver support
>
> Again, just a nit: a license mismatch.
>
> On Thu, 2015-05-21 at 22:37 +0530, Kedareswara rao Appana wrote:
>
> > + * 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.
>
> > +MODULE_LICENSE("GPL v2");
>
> As I said in the message I sent a short while ago: here too I think that either
> the comment at the top of this file or the ident used in the
> MODULE_LICENSE() macro needs to change.

Ok Will fix it in the next version of the patch.

Regards,
Kedar.

>
> Thanks,
>
>
> Paul Bolle



This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m???? ????????I?

2015-06-09 06:03:41

by Michal Simek

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

Hi Paul,

On 05/22/2015 12:30 PM, Paul Bolle wrote:
> Again, just a nit: a license mismatch.
>
> On Thu, 2015-05-21 at 22:37 +0530, Kedareswara rao Appana wrote:
>
>> + * 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.
>
>> +MODULE_LICENSE("GPL v2");
>
> As I said in the message I sent a short while ago: here too I think that
> either the comment at the top of this file or the ident used in the
> MODULE_LICENSE() macro needs to change.

This is not just the problem with this driver but with others too.
Have you sent any patch to add GPL v2+ to license.h?

Also sort of checking for this will be great. Julia?

Thanks,
Michal

--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: http://www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform



Attachments:
signature.asc (198.00 B)
OpenPGP digital signature

2015-06-09 06:11:13

by Julia Lawall

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support



On Tue, 9 Jun 2015, Michal Simek wrote:

> Hi Paul,
>
> On 05/22/2015 12:30 PM, Paul Bolle wrote:
> > Again, just a nit: a license mismatch.
> >
> > On Thu, 2015-05-21 at 22:37 +0530, Kedareswara rao Appana wrote:
> >
> >> + * 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.
> >
> >> +MODULE_LICENSE("GPL v2");
> >
> > As I said in the message I sent a short while ago: here too I think that
> > either the comment at the top of this file or the ident used in the
> > MODULE_LICENSE() macro needs to change.
>
> This is not just the problem with this driver but with others too.
> Have you sent any patch to add GPL v2+ to license.h?
>
> Also sort of checking for this will be great. Julia?

If this requires checking the contents of comment, Coccinelle currently
can't help with that. Perhaps an idea would be to just do a grep on the
file. So if I find MODULE_LICENSE("GPL v2") and then grepping for "either
vresion 2" gives success, then there is a problem? It's obviously not
foolproof, but perhaps it could be helpful.

julia

2015-06-09 07:09:50

by Michal Simek

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On 06/09/2015 08:10 AM, Julia Lawall wrote:
>
>
> On Tue, 9 Jun 2015, Michal Simek wrote:
>
>> Hi Paul,
>>
>> On 05/22/2015 12:30 PM, Paul Bolle wrote:
>>> Again, just a nit: a license mismatch.
>>>
>>> On Thu, 2015-05-21 at 22:37 +0530, Kedareswara rao Appana wrote:
>>>
>>>> + * 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.
>>>
>>>> +MODULE_LICENSE("GPL v2");
>>>
>>> As I said in the message I sent a short while ago: here too I think that
>>> either the comment at the top of this file or the ident used in the
>>> MODULE_LICENSE() macro needs to change.
>>
>> This is not just the problem with this driver but with others too.
>> Have you sent any patch to add GPL v2+ to license.h?
>>
>> Also sort of checking for this will be great. Julia?
>
> If this requires checking the contents of comment, Coccinelle currently
> can't help with that. Perhaps an idea would be to just do a grep on the
> file. So if I find MODULE_LICENSE("GPL v2") and then grepping for "either
> vresion 2" gives success, then there is a problem? It's obviously not
> foolproof, but perhaps it could be helpful.

Having some sort of checking somewhere will be great. checkpatch?
zero-day testing system?

Thanks,
Michal

--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: http://www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform



Attachments:
signature.asc (198.00 B)
OpenPGP digital signature

2015-06-09 07:22:09

by Paul Bolle

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On Tue, 2015-06-09 at 08:03 +0200, Michal Simek wrote:
> Have you sent any patch to add GPL v2+ to license.h?

"GPL" already means GPL v2 or later (see include/linux/module.h).

Thanks,


Paul Bolle

2015-06-09 07:27:51

by Michal Simek

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On 06/09/2015 09:21 AM, Paul Bolle wrote:
> On Tue, 2015-06-09 at 08:03 +0200, Michal Simek wrote:
>> Have you sent any patch to add GPL v2+ to license.h?
>
> "GPL" already means GPL v2 or later (see include/linux/module.h).

ok. I see.

Thanks,
Michal

--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: http://www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform



Attachments:
signature.asc (198.00 B)
OpenPGP digital signature

2015-06-09 08:08:36

by Julia Lawall

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support



On Tue, 9 Jun 2015, Michal Simek wrote:

> On 06/09/2015 09:21 AM, Paul Bolle wrote:
> > On Tue, 2015-06-09 at 08:03 +0200, Michal Simek wrote:
> >> Have you sent any patch to add GPL v2+ to license.h?
> >
> > "GPL" already means GPL v2 or later (see include/linux/module.h).
>
> ok. I see.

So there is nothing to do? Or are there still cases that could be
interesting?

julia

2015-06-09 08:15:33

by Paul Bolle

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On Tue, 2015-06-09 at 09:09 +0200, Michal Simek wrote:
> On 06/09/2015 08:10 AM, Julia Lawall wrote:
> > On Tue, 9 Jun 2015, Michal Simek wrote:
> >> Also sort of checking for this will be great. Julia?
> >
> > If this requires checking the contents of comment, Coccinelle currently
> > can't help with that. Perhaps an idea would be to just do a grep on the
> > file. So if I find MODULE_LICENSE("GPL v2") and then grepping for "either
> > vresion 2" gives success, then there is a problem? It's obviously not
> > foolproof, but perhaps it could be helpful.
>
> Having some sort of checking somewhere will be great. checkpatch?
> zero-day testing system?

Mistakes I've seen made since I started checking this stuff (a few
months ago):
- typos in the license ident, say "GPLv2", "GPL V2", or "BSD": generates
a warning when module is loaded and taints kernel. People still get this
wrong. A test in checkpatch for these typos was submitted a while ago,
but it never got added;
- not adding MODULE_LICENSE() to a module: also generates a warning when
module is loaded and taints kernel. People still get this wrong;
- adding MODULE_LICENSE() to built-in only code: pointless at best, and
annoying for reviewers ("Hey, did the submitter intend to write built-in
only code or modular code?");
- using "Dual BSD/GPL" but not a trace of the BSD license blurb in
sight, while adding that blurb is one of the very few requirements this
license actually has;
- license mismatch, say comment blurb states "GPL v2 (or later)" but
MODULE_LICENSE() ident states "GPL v2" only (or vice versa): very easy
mistake to make, happens once or twice a week.

Did I miss anything in that list?

I'm afraid that most of the above can only be caught reliably by
attention to detail by submitters and reviewers. That's a pity, because
checking for that stuff is about as boring as it gets. (What does that
say about me?)

Thanks,


Paul Bolle

2015-06-09 08:27:58

by Paul Bolle

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On Tue, 2015-06-09 at 10:08 +0200, Julia Lawall wrote:
> So there is nothing to do? Or are there still cases that could be
> interesting?

See my reply to Michal.

I think that, unless we come up with a new, much simpler way to add
license info to modules, we're stuck with doing the boring checks this
currently requires. And, of course, that new way, whatever that might
be, can probably not just replace the many thousands instances of the
MODULE_LICENSE() macro that there currently are. People being not to
keen on seeing their code being, well, relicensed.


Paul Bolle

2015-06-09 10:06:14

by Julia Lawall

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support



On Tue, 9 Jun 2015, Paul Bolle wrote:

> On Tue, 2015-06-09 at 09:09 +0200, Michal Simek wrote:
> > On 06/09/2015 08:10 AM, Julia Lawall wrote:
> > > On Tue, 9 Jun 2015, Michal Simek wrote:
> > >> Also sort of checking for this will be great. Julia?
> > >
> > > If this requires checking the contents of comment, Coccinelle currently
> > > can't help with that. Perhaps an idea would be to just do a grep on the
> > > file. So if I find MODULE_LICENSE("GPL v2") and then grepping for "either
> > > vresion 2" gives success, then there is a problem? It's obviously not
> > > foolproof, but perhaps it could be helpful.
> >
> > Having some sort of checking somewhere will be great. checkpatch?
> > zero-day testing system?
>
> Mistakes I've seen made since I started checking this stuff (a few
> months ago):
> - typos in the license ident, say "GPLv2", "GPL V2", or "BSD": generates
> a warning when module is loaded and taints kernel. People still get this
> wrong. A test in checkpatch for these typos was submitted a while ago,
> but it never got added;
> - not adding MODULE_LICENSE() to a module: also generates a warning when
> module is loaded and taints kernel. People still get this wrong;
> - adding MODULE_LICENSE() to built-in only code: pointless at best, and
> annoying for reviewers ("Hey, did the submitter intend to write built-in
> only code or modular code?");
> - using "Dual BSD/GPL" but not a trace of the BSD license blurb in
> sight, while adding that blurb is one of the very few requirements this
> license actually has;
> - license mismatch, say comment blurb states "GPL v2 (or later)" but
> MODULE_LICENSE() ident states "GPL v2" only (or vice versa): very easy
> mistake to make, happens once or twice a week.
>
> Did I miss anything in that list?
>
> I'm afraid that most of the above can only be caught reliably by
> attention to detail by submitters and reviewers. That's a pity, because
> checking for that stuff is about as boring as it gets. (What does that
> say about me?)

There has been some research in this direction:

A sentence-matching method for automatic license identification of source
code files
Daniel M. German, Yuki Manabe, Katsuro Inoue

The reuse of free and open source software (FOSS) components is becoming
more prevalent. One of the major challenges in finding the right component
is finding one that has a license that is e for its intended use. The
license of a FOSS component is determined by the licenses of its source
code files. In this paper, we describe the challenges of identifying the
license under which source code is made available, and propose a
sentence-based matching algorithm to automatically do it. We demonstrate
the feasibility of our approach by implementing a tool named Ninka. We
performed an evaluation that shows that Ninka outperforms other methods of
license identification in precision and speed. We also performed an
empirical study on 0.8 million source code files of Debian that highlight
interesting facts about the manner in which licenses are used by FOSS.

If you google for the paper title, you come across a pdf of the paper.

There seems to be a tool available as well:

http://ninka.turingmachine.org/

julia

2015-06-09 10:42:09

by Michal Simek

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On 06/09/2015 10:15 AM, Paul Bolle wrote:
> On Tue, 2015-06-09 at 09:09 +0200, Michal Simek wrote:
>> On 06/09/2015 08:10 AM, Julia Lawall wrote:
>>> On Tue, 9 Jun 2015, Michal Simek wrote:
>>>> Also sort of checking for this will be great. Julia?
>>>
>>> If this requires checking the contents of comment, Coccinelle currently
>>> can't help with that. Perhaps an idea would be to just do a grep on the
>>> file. So if I find MODULE_LICENSE("GPL v2") and then grepping for "either
>>> vresion 2" gives success, then there is a problem? It's obviously not
>>> foolproof, but perhaps it could be helpful.
>>
>> Having some sort of checking somewhere will be great. checkpatch?
>> zero-day testing system?
>
> Mistakes I've seen made since I started checking this stuff (a few
> months ago):
> - typos in the license ident, say "GPLv2", "GPL V2", or "BSD": generates
> a warning when module is loaded and taints kernel. People still get this
> wrong. A test in checkpatch for these typos was submitted a while ago,
> but it never got added;

Any reason for that? just lost or any problem ?

> - not adding MODULE_LICENSE() to a module: also generates a warning when
> module is loaded and taints kernel. People still get this wrong;
> - adding MODULE_LICENSE() to built-in only code: pointless at best, and
> annoying for reviewers ("Hey, did the submitter intend to write built-in
> only code or modular code?");
> - using "Dual BSD/GPL" but not a trace of the BSD license blurb in
> sight, while adding that blurb is one of the very few requirements this
> license actually has;
> - license mismatch, say comment blurb states "GPL v2 (or later)" but
> MODULE_LICENSE() ident states "GPL v2" only (or vice versa): very easy
> mistake to make, happens once or twice a week.

What do you mean by vice versa?
GPL v2 header and MODULE_LICENSE("GPL") should be fine right?

>
> Did I miss anything in that list?

I think you miss MODULE_ALIAS problems.
https://lkml.org/lkml/2014/3/17/301

>
> I'm afraid that most of the above can only be caught reliably by
> attention to detail by submitters and reviewers. That's a pity, because
> checking for that stuff is about as boring as it gets. (What does that
> say about me?)

yep. I have never looked at the details about these license module
stuff. But definitely great to have this list - will record it and keep
my eye on our xilinx drivers.

BTW: Some time ago we discussed SPDX License Identifier which could
simplify license checking.
https://lkml.org/lkml/2014/2/21/21

Interesting also is that selftests are using just "Licensed under the
GPLv2."

Thanks,
Michal

--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: http://www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform



Attachments:
signature.asc (198.00 B)
OpenPGP digital signature

2015-06-09 11:59:52

by Paul Bolle

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On Tue, 2015-06-09 at 12:41 +0200, Michal Simek wrote:
> On 06/09/2015 10:15 AM, Paul Bolle wrote:
> > Mistakes I've seen made since I started checking this stuff (a few
> > months ago):
> > - typos in the license ident, say "GPLv2", "GPL V2", or "BSD": generates
> > a warning when module is loaded and taints kernel. People still get this
> > wrong. A test in checkpatch for these typos was submitted a while ago,
> > but it never got added;
>
> Any reason for that? just lost or any problem ?

Submitter lost interest, I guess. Check
https://lkml.org/lkml/2015/5/22/279 and note that there was no response.

> > - not adding MODULE_LICENSE() to a module: also generates a warning when
> > module is loaded and taints kernel. People still get this wrong;
> > - adding MODULE_LICENSE() to built-in only code: pointless at best, and
> > annoying for reviewers ("Hey, did the submitter intend to write built-in
> > only code or modular code?");
> > - using "Dual BSD/GPL" but not a trace of the BSD license blurb in
> > sight, while adding that blurb is one of the very few requirements this
> > license actually has;
> > - license mismatch, say comment blurb states "GPL v2 (or later)" but
> > MODULE_LICENSE() ident states "GPL v2" only (or vice versa): very easy
> > mistake to make, happens once or twice a week.
>
> What do you mean by vice versa?
> GPL v2 header and MODULE_LICENSE("GPL") should be fine right?

Not really. The license in the comment at the top of the file is just
GPL v2, while the MODULE_LICENSE ident adds "or later" and thus the
right to "uplicense". So which is it: just "GPL v2" or "GPL v2 (or
later)"? Can't say in that case.

> > Did I miss anything in that list?
>
> I think you miss MODULE_ALIAS problems.
> https://lkml.org/lkml/2014/3/17/301

That's outside of the license stuff, but thanks for thye pointer anyway.

> > I'm afraid that most of the above can only be caught reliably by
> > attention to detail by submitters and reviewers. That's a pity, because
> > checking for that stuff is about as boring as it gets. (What does that
> > say about me?)
>
> yep. I have never looked at the details about these license module
> stuff. But definitely great to have this list - will record it and keep
> my eye on our xilinx drivers.
>
> BTW: Some time ago we discussed SPDX License Identifier which could
> simplify license checking.
> https://lkml.org/lkml/2014/2/21/21

I think I saw that fly by. Wasn't that idea shot down?

Thanks,


Paul Bolle

2015-06-09 12:12:59

by Michal Simek

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On 06/09/2015 01:59 PM, Paul Bolle wrote:
> On Tue, 2015-06-09 at 12:41 +0200, Michal Simek wrote:
>> On 06/09/2015 10:15 AM, Paul Bolle wrote:
>>> Mistakes I've seen made since I started checking this stuff (a few
>>> months ago):
>>> - typos in the license ident, say "GPLv2", "GPL V2", or "BSD": generates
>>> a warning when module is loaded and taints kernel. People still get this
>>> wrong. A test in checkpatch for these typos was submitted a while ago,
>>> but it never got added;
>>
>> Any reason for that? just lost or any problem ?
>
> Submitter lost interest, I guess. Check
> https://lkml.org/lkml/2015/5/22/279 and note that there was no response.

will see.


>>> - not adding MODULE_LICENSE() to a module: also generates a warning when
>>> module is loaded and taints kernel. People still get this wrong;
>>> - adding MODULE_LICENSE() to built-in only code: pointless at best, and
>>> annoying for reviewers ("Hey, did the submitter intend to write built-in
>>> only code or modular code?");
>>> - using "Dual BSD/GPL" but not a trace of the BSD license blurb in
>>> sight, while adding that blurb is one of the very few requirements this
>>> license actually has;
>>> - license mismatch, say comment blurb states "GPL v2 (or later)" but
>>> MODULE_LICENSE() ident states "GPL v2" only (or vice versa): very easy
>>> mistake to make, happens once or twice a week.
>>
>> What do you mean by vice versa?
>> GPL v2 header and MODULE_LICENSE("GPL") should be fine right?
>
> Not really. The license in the comment at the top of the file is just
> GPL v2, while the MODULE_LICENSE ident adds "or later" and thus the
> right to "uplicense". So which is it: just "GPL v2" or "GPL v2 (or
> later)"? Can't say in that case.

ok. Will check all our drivers we have to get it synchronized but I
expect that a lot of drivers have problems there.

>>> Did I miss anything in that list?
>>
>> I think you miss MODULE_ALIAS problems.
>> https://lkml.org/lkml/2014/3/17/301
>
> That's outside of the license stuff, but thanks for thye pointer anyway.
>
>>> I'm afraid that most of the above can only be caught reliably by
>>> attention to detail by submitters and reviewers. That's a pity, because
>>> checking for that stuff is about as boring as it gets. (What does that
>>> say about me?)
>>
>> yep. I have never looked at the details about these license module
>> stuff. But definitely great to have this list - will record it and keep
>> my eye on our xilinx drivers.
>>
>> BTW: Some time ago we discussed SPDX License Identifier which could
>> simplify license checking.
>> https://lkml.org/lkml/2014/2/21/21
>
> I think I saw that fly by. Wasn't that idea shot down?

Not sure about current status.

Thanks,
Michal

--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: http://www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform



Attachments:
signature.asc (198.00 B)
OpenPGP digital signature

2015-06-09 12:25:25

by Paul Bolle

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On Tue, 2015-06-09 at 14:12 +0200, Michal Simek wrote
> ok. Will check all our drivers we have to get it synchronized but I
> expect that a lot of drivers have problems there.

So do I. Cleaning that all up would add a lot of churn. I'm _not_
volunteering to do that.

What I decided to do was to (try to) comment on each patch that adds
another license mismatch. The idea being that this might annoy someone
into suggesting a (mostly) fool proof alternative to MODULE_LICENSE().
That didn't really work out yet (though Julia's and your response is
encouraging)

On the sunny side I note that very few new mismatches get added (at
least, I tricked myself into believing that).

Thanks,


Paul Bolle

2015-06-09 12:40:03

by Michal Simek

[permalink] [raw]
Subject: Re: [PATCH v4 2/2] dma: Add Xilinx AXI Central Direct Memory Access Engine driver support

On 06/09/2015 02:24 PM, Paul Bolle wrote:
> On Tue, 2015-06-09 at 14:12 +0200, Michal Simek wrote
>> ok. Will check all our drivers we have to get it synchronized but I
>> expect that a lot of drivers have problems there.
>
> So do I. Cleaning that all up would add a lot of churn. I'm _not_
> volunteering to do that.

Wolfram? You have been pretty successful with fixing owner field.
This looks like similar task.

>
> What I decided to do was to (try to) comment on each patch that adds
> another license mismatch. The idea being that this might annoy someone
> into suggesting a (mostly) fool proof alternative to MODULE_LICENSE().
> That didn't really work out yet (though Julia's and your response is
> encouraging)
>
> On the sunny side I note that very few new mismatches get added (at
> least, I tricked myself into believing that).

I expect that they will still come till this is properly reported by any
tool. And fixed everywhere because people just c&p drivers.

Thanks,
Michal