Thread (1 message) 1 message, 1 author, 2014-05-07

Re: [PATCH v2] DMA: add a driver for AMBA AXI NBPF DMAC IP cores

From: Vinod Koul <hidden>
Date: 2014-05-07 06:44:53

On Sat, Apr 26, 2014 at 02:03:44PM +0200, Guennadi Liakhovetski wrote:
This patch adds a driver for NBPF DMAC IP cores from Renesas, designed for
the AMBA AXI bus.
 
quoted hunk
diff --git a/Documentation/devicetree/bindings/dma/nbpfaxi.txt b/Documentation/devicetree/bindings/dma/nbpfaxi.txt
new file mode 100644
index 0000000..d5e2522
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/nbpfaxi.txt
@@ -0,0 +1,61 @@
+* Renesas "Type-AXI" NBPFAXI* DMA controllers
+
+* DMA controller
+
+Required properties
+
+- compatible:	must be one of
+		"renesas,nbpfaxi64dmac1b4"
+		"renesas,nbpfaxi64dmac1b8"
+		"renesas,nbpfaxi64dmac1b16"
+		"renesas,nbpfaxi64dmac4b4"
+		"renesas,nbpfaxi64dmac4b8"
+		"renesas,nbpfaxi64dmac4b16"
+		"renesas,nbpfaxi64dmac8b4"
+		"renesas,nbpfaxi64dmac8b8"
+		"renesas,nbpfaxi64dmac8b16"
+- #dma-cells:	must be 2: the first integer is a terminal number, to which this
+		slave is connected, the second one is flags. Flags is a bitmask
+		with the following bits defined:
+
+#define NBPF_SLAVE_RQ_HIGH	1
+#define NBPF_SLAVE_RQ_LOW	2
+#define NBPF_SLAVE_RQ_LEVEL	4
+
+Optional properties:
+
+You can use dma-channels and dma-requests as described in dma.txt, although they
+won't be used, this information is derived from the compatibility string.
+
+Example:
+
+	dma: dma-controller@48000000 {
+		compatible = "renesas,nbpfaxi64dmac8b4";
+		reg = <0x48000000 0x400>;
+		interrupts = <0 12 0x4
+			      0 13 0x4
+			      0 14 0x4
+			      0 15 0x4
+			      0 16 0x4
+			      0 17 0x4
+			      0 18 0x4
+			      0 19 0x4>;
+		#dma-cells = <2>;
+		dma-channels = <8>;
+		dma-requests = <8>;
+	};
+
+* DMA client
+
+Required properties:
+
+dmas and dma-names are required, as described in dma.txt.
+
+Example:
+
+#include <dt-bindings/dma/nbpfaxi.h>
+
+...
+		dmas = <&dma 0 (NBPF_SLAVE_RQ_HIGH | NBPF_SLAVE_RQ_LEVEL)
+			&dma 1 (NBPF_SLAVE_RQ_HIGH | NBPF_SLAVE_RQ_LEVEL)>;
+		dma-names = "rx", "tx";
Pls split the DT bindings to seprate patch. This part needs ack from DT folks
+static size_t nbpf_xfer_size(struct nbpf_device *nbpf,
+			     enum dma_slave_buswidth width, u32 burst)
+{
+	size_t size;
+
+	if (!burst)
+		burst = 1;
+
+	switch (width) {
+	case DMA_SLAVE_BUSWIDTH_8_BYTES:
+		size = 8 * burst;
+		break;
+	case DMA_SLAVE_BUSWIDTH_4_BYTES:
+		size = 4 * burst;
+		break;
+	case DMA_SLAVE_BUSWIDTH_2_BYTES:
+		size = 2 * burst;
why not		size = width * burst; 
for all these three cases?
+		break;
+	default:
+		pr_warn("%s(): invalid bus width %u\n", __func__, width);
+	case DMA_SLAVE_BUSWIDTH_1_BYTE:
+		size = burst;
this would fit too in above :)
+static void nbpf_cookie_update(struct nbpf_channel *chan, dma_cookie_t cookie)
+{
+	dma_cookie_t forgotten = cookie - NBPF_STATUS_KEEP;
+
+	if (cookie < NBPF_STATUS_KEEP && !chan->cookie_forgotten)
+		/* Not forgetting yet */
+		return;
+
+	if (forgotten < DMA_MIN_COOKIE)
+		/* Wrapped */
+		forgotten = (DMA_MAX_COOKIE & ~NBPF_STATUS_MASK) + cookie;
+	chan->cookie_forgotten = forgotten;
+}
why dont use core handler for this? Why do you need to track forgotten?
+
+static bool nbpf_cookie_in_cache(struct nbpf_channel *chan,
+		dma_cookie_t cookie, struct dma_tx_state *state)
+{
+	if (cookie > chan->cookie_forgotten)
+		return true;
+
+	/*
+	 * We still remember the cookie, if it has wrapped beyond INT_MAX:
+	 * (1) forgotten is almost INT_MAX
+	 * cookie_forgotten >> NBPF_STATUS_SHIFT == DMA_MAX_COOKIE >> NBPF_STATUS_SHIFT
+	 * and enquired is small
+	 * (2)
+	 * cookie & ~NBPF_STATUS_MASK == 0
Again this logic is handled so driver shoudl worry about this
+	 */
+
+	return chan->cookie_forgotten >> NBPF_STATUS_SHIFT ==
+		DMA_MAX_COOKIE >> NBPF_STATUS_SHIFT &&
+		!(cookie < ~NBPF_STATUS_MASK);
+}
+
+static enum dma_status nbpf_tx_status(struct dma_chan *dchan,
+		dma_cookie_t cookie, struct dma_tx_state *state)
+{
+	struct nbpf_channel *chan = nbpf_to_chan(dchan);
+	enum dma_status status = dma_cookie_status(dchan, cookie, state);
+	dma_cookie_t running = chan->running ? chan->running->async_tx.cookie : -EINVAL;
+
+	if (chan->paused)
+		status = DMA_PAUSED;
+
+	/* Note: we cannot return residues for old cookies */
??? If cookie is completed then reside is 0. So how is this comment valid?
+	if (state && cookie == running) {
+		state->residue = nbpf_bytes_left(chan);
+		dev_dbg(dchan->device->dev, "%s(): residue %u\n", __func__,
+			state->residue);
+	}
+
+	if (status == DMA_IN_PROGRESS || status == DMA_PAUSED)
+		return status;
no residue here?
+
+	if (nbpf_cookie_in_cache(chan, cookie, state))
+		return nbpf_cookie_cached(chan, cookie, state);
+
+	return status;
+}
+
+static int nbpf_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
+			unsigned long arg)
+{
+	struct nbpf_channel *chan = nbpf_to_chan(dchan);
+	struct dma_slave_config *config;
+
+	dev_dbg(dchan->device->dev, "Entry %s(%d)\n", __func__, cmd);
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		dev_dbg(dchan->device->dev, "Terminating\n");
+		nbpf_chan_halt(chan);
+		nbpf_chan_idle(chan);
+		break;
+	case DMA_SLAVE_CONFIG:
+		if (!arg)
+			return -EINVAL;
+		config = (struct dma_slave_config *)arg;
+
+		/*
+		 * We could check config->slave_id to match chan->terminal here,
+		 * but with DT they would be coming from the same source, so
+		 * such a check would be superflous
+		 */
+
+		switch (config->direction) {
+		case DMA_MEM_TO_DEV:
+			chan->slave_addr = config->dst_addr;
+			chan->slave_width = nbpf_xfer_size(chan->nbpf,
+							config->dst_addr_width, 1);
+			chan->slave_burst = nbpf_xfer_size(chan->nbpf,
+							config->dst_addr_width,
+							config->dst_maxburst);
+			break;
+		case DMA_DEV_TO_MEM:
+			chan->slave_addr = config->src_addr;
+			chan->slave_width = nbpf_xfer_size(chan->nbpf,
+							config->src_addr_width, 1);
+			chan->slave_burst = nbpf_xfer_size(chan->nbpf,
+							config->src_addr_width,
+							config->src_maxburst);
pls store all as direction makes no sense here and will be removed.
Now based on descriptor direction you need to use one set of above.
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case DMA_PAUSE:
+		chan->paused = true;
+		nbpf_pause(chan);
+		break;
+	case DMA_RESUME:
+		/* Leave unimplemented until we get a use case. */
why not remove?
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static struct dma_async_tx_descriptor *nbpf_prep_sg(struct nbpf_channel *chan,
+		struct scatterlist *src_sg, struct scatterlist *dst_sg,
+		size_t len, enum dma_transfer_direction direction,
+		unsigned long flags)
+{
+	struct nbpf_link_desc *ldesc;
+	struct scatterlist *mem_sg;
+	struct nbpf_desc *desc;
+	bool inc_src, inc_dst;
+	int i = 0;
+
+	switch (direction) {
+	case DMA_DEV_TO_MEM:
+		mem_sg = dst_sg;
+		inc_src = false;
+		inc_dst = true;
+		break;
empty line here and similar instance pls
+	case DMA_MEM_TO_DEV:
+		mem_sg = src_sg;
+		inc_src = true;
+		inc_dst = false;
+		break;
+	default:
+	case DMA_MEM_TO_MEM:
+		mem_sg = src_sg;
+		inc_src = true;
+		inc_dst = true;
+	}
+
+	desc = nbpf_desc_get(chan, len);
+	if (!desc)
+		return NULL;
+
+	desc->async_tx.flags = flags;
+	desc->async_tx.cookie = -EBUSY;
+	desc->user_wait = false;
+
+static int nbpf_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *of_id = of_match_device(nbpf_match, dev);
+	struct device_node *np = dev->of_node;
+	struct nbpf_device *nbpf;
+	struct dma_device *dma_dev;
+	struct resource *iomem, *irq_res;
+	const struct nbpf_config *cfg;
+	int num_channels;
+	int ret, irq, eirq, i;
+	int irqbuf[9] /* maximum 8 channels + error IRQ */;
+	unsigned int irqs = 0;
+
+	BUILD_BUG_ON(sizeof(struct nbpf_desc_page) > PAGE_SIZE);
+
+	/* DT only */
+	if (!np || !of_id || !of_id->data)
+		return -ENODEV;
+
+	cfg = of_id->data;
+	num_channels = cfg->num_channels;
+
+	nbpf = devm_kzalloc(dev, sizeof(*nbpf) + num_channels *
+			    sizeof(nbpf->chan[0]), GFP_KERNEL);
I think we have devm_kcalloc for these things?

-- 
~Vinod
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help