Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1541605 > unrolled thread

[PATCH 00/12] Eberspaecher Flexcard PMC II base support

Started byHolger Dengler <dengler@linutronix.de>
First post2016-12-14 01:20 +0100
Last post2016-12-19 12:00 +0100
Articles 5 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 00/12] Eberspaecher Flexcard PMC II base support Holger Dengler <dengler@linutronix.de> - 2016-12-14 01:20 +0100
    [PATCH 02/12] mfd: flexcard: add flexcard misc mfd-cell Holger Dengler <dengler@linutronix.de> - 2016-12-14 01:20 +0100
    [PATCH 12/12] dma: Flexcard DMA ringbuffer demux driver Holger Dengler <dengler@linutronix.de> - 2016-12-14 01:20 +0100
      Re: [PATCH 12/12] dma: Flexcard DMA ringbuffer demux driver Vinod Koul <vinod.koul@intel.com> - 2016-12-15 05:50 +0100
        Re: [PATCH 12/12] dma: Flexcard DMA ringbuffer demux driver Holger Dengler <dengler@linutronix.de> - 2016-12-19 12:00 +0100

#1541605 — [PATCH 00/12] Eberspaecher Flexcard PMC II base support

FromHolger Dengler <dengler@linutronix.de>
Date2016-12-14 01:20 +0100
Subject[PATCH 00/12] Eberspaecher Flexcard PMC II base support
Message-ID<sO5sB-7Vh-5@gated-at.bofh.it>
The Eberspaecher Flexcard PMC II is a PMC (PCI Mezzanine Card) II
carrier board. The carrier board can take up to 4 exchangeable physical
layer boards for CAN, FlexRay or Ethernet.
This patchset adds support for the common infrastructure of the carrier
board.

This patch series apply on v4.9.

First post:  http://www.spinics.net/lists/netdev/msg246290.html
Second post: http://www.spinics.net/lists/kernel/msg1954275.html

According to the comments regarding our first posting, the MFD driver
patchset has been split up into separate functional parts.

According to the comments regarding our second port, we moved the
separated driver to their particular subsystems. All other comments
are also reflected.

The timer functionality was wrongly named as clocksource in the second post,
although it is a posix_clock. We renamed it and moved it together with the
misc_device funtions to drivers/misc/. If someone know a better place for
the posix_clock, please let me know.

The irq part of the mfd driver has been mainly reworked (thanks to Thomas
and Sebastian for their input). The irq-demux is now implementet without a
loop and the irq_chips share the irq-table and functions.

Holger Dengler (12):
  mfd: Eberspaecher Flexcard PMC II Carrier Board support
  mfd: flexcard: add flexcard misc mfd-cell
  mfd: flexcard: add posix clock mfd-cell
  mfd: flexcard: add interrupt support
  mfd: flexcard: add DMA interrupts
  mfd: flexcard: add DMA device
  mfd: flexcard: add UIO IRQ devices
  misc: Flexcard misc device support
  misc: flexcard: add device attributes
  misc: Flexcard basic timestamp counter support
  misc: flexcard: Support timestamp trigger selection
  dma: Flexcard DMA ringbuffer demux driver

 drivers/dma/Kconfig                 |   9 +
 drivers/dma/Makefile                |   1 +
 drivers/dma/flexcard/Makefile       |   2 +
 drivers/dma/flexcard/core.c         | 292 ++++++++++++++++++++++
 drivers/dma/flexcard/flexcard-dma.h | 218 +++++++++++++++++
 drivers/dma/flexcard/parser.c       | 227 +++++++++++++++++
 drivers/mfd/Kconfig                 |  14 ++
 drivers/mfd/Makefile                |   3 +
 drivers/mfd/flexcard_core.c         | 476 ++++++++++++++++++++++++++++++++++++
 drivers/mfd/flexcard_irq.c          | 305 +++++++++++++++++++++++
 drivers/misc/Kconfig                |  15 ++
 drivers/misc/Makefile               |   2 +
 drivers/misc/flexcard_misc.c        | 361 +++++++++++++++++++++++++++
 drivers/misc/flexcard_posixclock.c  | 295 ++++++++++++++++++++++
 include/linux/mfd/flexcard.h        | 116 +++++++++
 include/uapi/linux/Kbuild           |   1 +
 include/uapi/linux/flexcard.h       |  80 ++++++
 17 files changed, 2417 insertions(+)
 create mode 100644 drivers/dma/flexcard/Makefile
 create mode 100644 drivers/dma/flexcard/core.c
 create mode 100644 drivers/dma/flexcard/flexcard-dma.h
 create mode 100644 drivers/dma/flexcard/parser.c
 create mode 100644 drivers/mfd/flexcard_core.c
 create mode 100644 drivers/mfd/flexcard_irq.c
 create mode 100644 drivers/misc/flexcard_misc.c
 create mode 100644 drivers/misc/flexcard_posixclock.c
 create mode 100644 include/linux/mfd/flexcard.h
 create mode 100644 include/uapi/linux/flexcard.h

-- 
2.1.4

[toc] | [next] | [standalone]


#1541606 — [PATCH 02/12] mfd: flexcard: add flexcard misc mfd-cell

FromHolger Dengler <dengler@linutronix.de>
Date2016-12-14 01:20 +0100
Subject[PATCH 02/12] mfd: flexcard: add flexcard misc mfd-cell
Message-ID<sO5sC-7Vh-43@gated-at.bofh.it>
In reply to#1541605
The Flexcard PCI BAR0 contain registers for configuration and
informational purpose. Add an appropriate MFD-cell for these registers.

Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
Signed-off-by: Holger Dengler <dengler@linutronix.de>
cc: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/flexcard_core.c  | 58 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/mfd/flexcard.h |  1 +
 2 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/flexcard_core.c b/drivers/mfd/flexcard_core.c
index e580971..2ee9089 100644
--- a/drivers/mfd/flexcard_core.c
+++ b/drivers/mfd/flexcard_core.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -25,11 +26,48 @@
 #define FLEXCARD_FR_OFFSET	0x4000
 #define FLEXCARD_FR_SIZE	0x2000
 
+#define FLEXCARD_CONF_START	0x000
+#define FLEXCARD_CONF_SIZE	0x13F
+#define FLEXCARD_NF_START	0x170
+#define FLEXCARD_NF_SIZE	0x7
+
+static DEFINE_IDA(flexcard_ida);
+
+static struct resource flexcard_misc_res[] = {
+	DEFINE_RES_MEM_NAMED(FLEXCARD_CONF_START,
+			     FLEXCARD_CONF_SIZE,
+			     "flexcard-conf"),
+	DEFINE_RES_MEM_NAMED(FLEXCARD_NF_START,
+			     FLEXCARD_NF_SIZE,
+			     "flexcard-nf"),
+};
+
+static struct mfd_cell flexcard_misc_dev[] = {
+	{
+		.name = "flexcard-misc",
+		.num_resources = ARRAY_SIZE(flexcard_misc_res),
+		.resources = flexcard_misc_res,
+	},
+};
+
 enum flexcard_cell_id {
 	FLEXCARD_CELL_CAN,
 	FLEXCARD_CELL_FLEXRAY,
 };
 
+static int flexcard_misc_setup(struct flexcard_device *priv)
+{
+	struct pci_dev *pdev = priv->pdev;
+
+	flexcard_misc_dev[0].id = priv->cardnr;
+	flexcard_misc_res[0].parent = &pdev->resource[0];
+	flexcard_misc_res[1].parent = &pdev->resource[0];
+
+	return mfd_add_devices(&pdev->dev, 0, flexcard_misc_dev,
+			       ARRAY_SIZE(flexcard_misc_dev),
+			       &pdev->resource[0], 0, NULL);
+}
+
 static int flexcard_tiny_can(struct flexcard_device *priv,
 			     int idx, int id, u32 offset)
 {
@@ -163,10 +201,23 @@ static int flexcard_probe(struct pci_dev *pdev,
 	fw_ver.reg = readl(&priv->bar0->conf.fc_fw_ver);
 	hw_ver.reg = readl(&priv->bar0->conf.fc_hw_ver);
 
+	ret = ida_simple_get(&flexcard_ida, 0, 0, GFP_KERNEL);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "could not get new Flexcard id:%d\n", ret);
+		goto out_unmap;
+	}
+	priv->cardnr = ret;
+
 	ret = flexcard_tiny_probe(priv);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to probe tinys: %d", ret);
-		goto out_unmap;
+		goto out_ida;
+	}
+
+	ret = flexcard_misc_setup(priv);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to probe tinys: %d", ret);
+		goto out_mfd_dev_remove;
 	}
 
 	dev_info(&pdev->dev, "HW %02x.%02x.%02x FW %02x.%02x.%02x\n",
@@ -175,6 +226,10 @@ static int flexcard_probe(struct pci_dev *pdev,
 
 	return 0;
 
+out_mfd_dev_remove:
+	mfd_remove_devices(&pdev->dev);
+out_ida:
+	ida_simple_remove(&flexcard_ida, priv->cardnr);
 out_unmap:
 	iounmap(priv->bar0);
 out_release:
@@ -190,6 +245,7 @@ static void flexcard_remove(struct pci_dev *pdev)
 	struct flexcard_device *priv = pci_get_drvdata(pdev);
 
 	mfd_remove_devices(&pdev->dev);
+	ida_simple_remove(&flexcard_ida, priv->cardnr);
 	iounmap(priv->bar0);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
index 362b909..4116305 100644
--- a/include/linux/mfd/flexcard.h
+++ b/include/linux/mfd/flexcard.h
@@ -94,6 +94,7 @@ struct fc_bar0 {
 } __packed;
 
 struct flexcard_device {
+	unsigned int cardnr;
 	struct pci_dev *pdev;
 	struct fc_bar0 __iomem *bar0;
 	struct mfd_cell *cells;
-- 
2.1.4

[toc] | [prev] | [next] | [standalone]


#1541608 — [PATCH 12/12] dma: Flexcard DMA ringbuffer demux driver

FromHolger Dengler <dengler@linutronix.de>
Date2016-12-14 01:20 +0100
Subject[PATCH 12/12] dma: Flexcard DMA ringbuffer demux driver
Message-ID<sO5sC-7Vh-47@gated-at.bofh.it>
In reply to#1541605
The Flexcard interface design split packet receive and transmit. All
received packets and card status information are multiplexed with a
Flexcard specific protocol and handled through a DMA capable ringbuffer.
The TX path has to poke each available component separate.

Add a Flexcard DMA ringbuffer driver and packet demultiplexer.

Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
Signed-off-by: Holger Dengler <dengler@linutronix.de>
cc: Vinod Koul <vinod.koul@intel.com>
---
 drivers/dma/Kconfig                 |   9 ++
 drivers/dma/Makefile                |   1 +
 drivers/dma/flexcard/Makefile       |   2 +
 drivers/dma/flexcard/core.c         | 292 ++++++++++++++++++++++++++++++++++++
 drivers/dma/flexcard/flexcard-dma.h | 218 +++++++++++++++++++++++++++
 drivers/dma/flexcard/parser.c       | 227 ++++++++++++++++++++++++++++
 drivers/mfd/Kconfig                 |   1 +
 include/linux/mfd/flexcard.h        |   4 +
 8 files changed, 754 insertions(+)
 create mode 100644 drivers/dma/flexcard/Makefile
 create mode 100644 drivers/dma/flexcard/core.c
 create mode 100644 drivers/dma/flexcard/flexcard-dma.h
 create mode 100644 drivers/dma/flexcard/parser.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 141aefb..b158544 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -40,6 +40,15 @@ config ASYNC_TX_ENABLE_CHANNEL_SWITCH
 config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
 	bool
 
+config FLEXCARD_DMA
+	tristate "DMA support for Eberspaecher Flexcard PMC II Carrier Board"
+	depends on MFD_FLEXCARD
+	help
+	  The Eberspaecher Flexcard PMC (PCI Mezzanine Card) II carrier
+	  board support one DMA capable receive ringbuffer for all devices.
+	  A card specific protocol is used to multiplex the received packets
+	  through the ringbuffer. Enable DMA and Packet parser.
+
 config DMA_ENGINE
 	bool
 
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index e4dc9ca..a9a5b3f 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o
 obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o
 obj-$(CONFIG_DW_DMAC_CORE) += dw/
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
+obj-$(CONFIG_FLEXCARD_DMA) += flexcard/
 obj-$(CONFIG_FSL_DMA) += fsldma.o
 obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
 obj-$(CONFIG_FSL_RAID) += fsl_raid.o
diff --git a/drivers/dma/flexcard/Makefile b/drivers/dma/flexcard/Makefile
new file mode 100644
index 0000000..62ae627
--- /dev/null
+++ b/drivers/dma/flexcard/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_FLEXCARD_DMA) += flexcard_dma.o
+flexcard_dma-objs := core.o parser.o
diff --git a/drivers/dma/flexcard/core.c b/drivers/dma/flexcard/core.c
new file mode 100644
index 0000000..6809840
--- /dev/null
+++ b/drivers/dma/flexcard/core.c
@@ -0,0 +1,292 @@
+/*
+ * Eberspächer Flexcard PMC II Carrier Board PCI Driver - DMA controller
+ *
+ * Copyright (c) 2014 - 2016, Linutronix GmbH
+ * Author: Benedikt Spranger <b.spranger@linutronix.de>
+ *         Holger Dengler <dengler@linutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/flexcard.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/flexcard.h>
+
+#include "flexcard-dma.h"
+
+/*
+ * Allocate twice the size of FLEXCARD_DMA_BUF_SIZE for the receiving
+ * ring buffer to easily handle wrap-arounds.
+ */
+#define DMA_TOTAL_BUF_SIZE		(2*FLEXCARD_DMA_BUF_SIZE)
+
+static int flexcard_dma_stop(struct flexcard_dma *dma)
+{
+	u32 __iomem *dma_ctrl = &dma->reg->dma_ctrl;
+	u32 __iomem *dma_stat = &dma->reg->dma_stat;
+	int retry;
+
+	writel(FLEXCARD_DMA_CTRL_STOP_REQ, dma_ctrl);
+
+	/*
+	 * DMA_IDLE bit reads 1 when the DMA state machine is in idle state
+	 * after a stop request, otherwise 0. DMA stop should complete in at
+	 * least 200us.
+	 */
+	retry = 200;
+	while (!(readl(dma_ctrl) & FLEXCARD_DMA_CTRL_DMA_IDLE) && retry--)
+		udelay(1);
+	if (!retry)
+		return -EBUSY;
+
+	/*
+	 * Check for max. 200us, if there are DMA jobs in progress.
+	 */
+	retry = 200;
+	while ((readl(dma_stat) & FLEXCARD_DMA_STAT_BUSY) && retry--)
+		udelay(1);
+
+	return retry ? 0 : -EBUSY;
+}
+
+static int flexcard_dma_reset(struct flexcard_dma *dma)
+{
+	u32 __iomem *dma_ctrl = &dma->reg->dma_ctrl;
+	int retry = 500;
+
+	writel(FLEXCARD_DMA_CTRL_RST_DMA, dma_ctrl);
+
+	/*
+	 * DMA_IDLE bit reads 1 when the DMA state machine is in idle state
+	 * after a reset request, otherwise 0. DMA reset should complete in
+	 * at least 5ms.
+	 */
+	while (!(readl(dma_ctrl) & FLEXCARD_DMA_CTRL_DMA_IDLE) && retry--)
+		udelay(10);
+
+	return retry ? 0 : -EIO;
+}
+
+static int flexcard_dma_setup(struct flexcard_dma *dma)
+{
+	int ret;
+
+	ret = flexcard_dma_reset(dma);
+	if (ret)
+		return ret;
+
+	writel(0x0, &dma->reg->dma_rptr);
+	writel(0x0, &dma->reg->dma_wptr);
+	writel(0x0, &dma->reg->dma_ctrl);
+
+	writeq(dma->phys, &dma->reg->dma_cba);
+	writel(FLEXCARD_DMA_BUF_SIZE, &dma->reg->dma_cbs);
+
+	return ret;
+}
+
+static irqreturn_t flexcard_dma_isr(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct flexcard_dma *dma = platform_get_drvdata(pdev);
+	u32 avail, parsed, rptr = dma->rptr;
+
+	avail = readl(&dma->reg->dma_cblr);
+	if (!avail)
+		return IRQ_NONE;
+
+	do {
+		u32 tocp = rptr + FLEXCARD_MAX_PAKET_SIZE;
+		/*
+		 * For simplicity the parser always looks at contiguous
+		 * buffer space.
+		 *
+		 * We ensure that by copying the eventually wrapped
+		 * bytes of the next message from the bottom of the
+		 * dma buffer to the space right after the dma buffer
+		 * which has been allocated just for that reason.
+		 */
+		if (tocp > FLEXCARD_DMA_BUF_SIZE) {
+			tocp &= FLEXCARD_DMA_BUF_MASK;
+			memcpy(dma->buf + FLEXCARD_DMA_BUF_SIZE,
+			       dma->buf, tocp);
+		}
+
+		parsed = flexcard_parse_packet(dma->buf + rptr, avail, dma);
+		if (parsed > avail) {
+			dev_err(&pdev->dev, "Parser overrun\n");
+			rptr = (rptr + parsed) & FLEXCARD_DMA_BUF_MASK;
+			break;
+		}
+		avail -= parsed;
+		rptr = (rptr + parsed) & FLEXCARD_DMA_BUF_MASK;
+	} while (parsed && avail);
+
+	/* Update the read pointer in the device if we processed data */
+	if (dma->rptr != rptr) {
+		dma->rptr = rptr;
+		writel(rptr, &dma->reg->dma_rptr);
+	} else {
+		/* This may happen if no packets has been parsed */
+		dev_err_ratelimited(&pdev->dev, "rptr unchanged\n");
+		return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t flexcard_dma_ovr(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct flexcard_dma *dma = platform_get_drvdata(pdev);
+	u32 stat;
+
+	/* check overflow flag */
+	stat = readl(&dma->reg->dma_stat);
+	if (!(stat & FLEXCARD_DMA_STAT_OFL))
+		return IRQ_NONE;
+
+	dev_err(&pdev->dev, "DMA buffer overflow\n");
+
+	writel(0x0, &dma->reg->dma_rptr);
+
+	/* reset overflow flag */
+	writel(FLEXCARD_DMA_STAT_OFL, &dma->reg->dma_stat);
+
+	return IRQ_HANDLED;
+}
+
+static int flexcard_dma_resource(struct platform_device *pdev)
+{
+	struct flexcard_dma *dma = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	dma->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!dma->reg) {
+		dev_err(&pdev->dev, "failed to map DMA register\n");
+		return -ENOMEM;
+	}
+
+	dma->irq = platform_get_irq(pdev, 0);
+	if (dma->irq < 0) {
+		dev_err(&pdev->dev, "failed to get CBL IRQ\n");
+		return -ENXIO;
+	}
+
+	dma->irq_ovr = platform_get_irq(pdev, 1);
+	if (dma->irq_ovr < 0) {
+		dev_err(&pdev->dev, "failed to get CO IRQ\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+
+static int flexcard_dma_probe(struct platform_device *pdev)
+{
+	const struct mfd_cell *cell;
+	struct flexcard_dma *dma;
+	int ret;
+
+	cell = mfd_get_cell(pdev);
+	if (!cell)
+		return -ENODEV;
+
+	dma = devm_kzalloc(&pdev->dev, sizeof(*dma), GFP_KERNEL);
+	if (!dma)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, dma);
+
+	dma->buf = dma_alloc_coherent(&pdev->dev, DMA_TOTAL_BUF_SIZE,
+				      &dma->phys, GFP_KERNEL);
+	if (!dma->buf) {
+		dev_err(&pdev->dev, "could not allocate DMA memory\n");
+		return -ENOMEM;
+	}
+
+	ret = flexcard_dma_resource(pdev);
+	if (ret)
+		goto out_free_buf;
+
+	ret = flexcard_dma_setup(dma);
+	if (ret) {
+		dev_err(&pdev->dev, "could not setup Flexcard DMA: %d\n", ret);
+		goto out_free_buf;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, dma->irq, NULL,
+					flexcard_dma_isr, IRQF_ONESHOT,
+					"flexcard-CBL", pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "could not request Flexcard DMA CBL IRQ\n");
+		goto out_free_buf;
+	}
+
+	ret = devm_request_irq(&pdev->dev, dma->irq_ovr, flexcard_dma_ovr, 0,
+			  "flexcard-CO", pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "could not request Flexcard DMA CO IRQ\n");
+		goto out_free_irq;
+	}
+
+	writel(FLEXCARD_DMA_CTRL_DMA_ENA, &dma->reg->dma_ctrl);
+	writel(0x300, &dma->reg->dma_cbcr);
+
+	dev_info(&pdev->dev, "Flexcard DMA registered");
+
+	return 0;
+
+out_free_irq:
+	writel(0x0, &dma->reg->dma_ctrl);
+out_free_buf:
+	dma_free_coherent(&pdev->dev, DMA_TOTAL_BUF_SIZE,
+			  dma->buf, dma->phys);
+	return ret;
+}
+
+static int flexcard_dma_remove(struct platform_device *pdev)
+{
+	struct flexcard_dma *dma = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = flexcard_dma_stop(dma);
+	if (ret) {
+		dev_err(&pdev->dev, "could not stop DMA state machine\n");
+		return ret;
+	}
+
+	dma_free_coherent(&pdev->dev, DMA_TOTAL_BUF_SIZE,
+			  dma->buf, dma->phys);
+
+	return ret;
+}
+
+static struct platform_driver flexcard_dma_driver = {
+	.probe		= flexcard_dma_probe,
+	.remove		= flexcard_dma_remove,
+	.driver		= {
+		.name   = "flexcard-dma",
+	}
+};
+
+module_platform_driver(flexcard_dma_driver);
+
+MODULE_AUTHOR("Holger Dengler <dengler@linutronix.de>");
+MODULE_AUTHOR("Benedikt Spranger <b.spranger@linutronix.de>");
+MODULE_DESCRIPTION("Eberspaecher Flexcard PMC II DMA Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:flexcard-dma");
diff --git a/drivers/dma/flexcard/flexcard-dma.h b/drivers/dma/flexcard/flexcard-dma.h
new file mode 100644
index 0000000..6fc4ccf
--- /dev/null
+++ b/drivers/dma/flexcard/flexcard-dma.h
@@ -0,0 +1,218 @@
+/*
+ * Eberspächer Flexcard PMC II Carrier Board PCI Driver - DMA controller
+ *
+ * Copyright (c) 2014 - 2016, Linutronix GmbH
+ * Author: Benedikt Spranger <b.spranger@linutronix.de>
+ *         Holger Dengler <dengler@linutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+#ifndef __FLEXCARD_DMA_H
+#define __FLEXCARD_DMA_H
+
+#define FLEXCARD_DMA_BUF_SIZE		0x200000
+#define FLEXCARD_DMA_BUF_MASK		(FLEXCARD_DMA_BUF_SIZE - 1)
+
+#define FLEXCARD_DMA_CTRL_DMA_ENA	(1 << 0)
+#define FLEXCARD_DMA_CTRL_MAN_ENA	(1 << 1)
+#define FLEXCARD_DMA_CTRL_STOP_REQ	(1 << 16)
+#define FLEXCARD_DMA_CTRL_DMA_IDLE	(1 << 17)
+#define FLEXCARD_DMA_CTRL_RST_DMA	(1 << 31)
+
+#define FLEXCARD_DMA_STAT_BUSY		(1 << 15)
+#define FLEXCARD_DMA_STAT_OFL		(1 << 31)
+
+#define FLEXCARD_MAX_PAKET_SIZE		0x200
+
+#define FLEXCARD_BUF_HEADER_LEN_SHIFT	15
+#define FLEXCARD_BUF_HEADER_LEN_MASK	0xfe
+
+#define FLEXCARD_CANIF_OFFSET		0x20
+
+struct flexcard_dma_reg {
+	u32 dma_ctrl;
+	u32 dma_stat;
+	u32 r1[2];
+	u64 dma_cba;
+	u32 dma_cbs;
+	u32 dma_txr;
+	u32 dma_irer;
+	u32 dma_irsr;
+	u32 r2[10];
+	u32 dma_cbcr;
+	u32 dma_cblr;
+	u32 r3[2];
+	u32 dma_itcr;
+	u32 dma_itr;
+	u32 r4[2];
+	u32 dma_wptr;
+	u32 dma_rptr;
+	u32 r5[2];
+} __packed;
+
+struct flexcard_dma {
+	int irq;
+	int irq_ovr;
+	u32 rptr;
+	void *buf;
+	dma_addr_t phys;
+	int nr_eray;
+	struct flexcard_dma_reg __iomem *reg;
+};
+
+enum fc_packet_type {
+	FC_PACKET_TYPE_INFO = 1,
+	FC_PACKET_TYPE_FLEXRAY_FRAME = 2,
+	FC_PACKET_TYPE_ERROR = 3,
+	FC_PACKET_TYPE_STATUS = 4,
+	FC_PACKET_TYPE_TRIGGER = 5,
+	FC_PACKET_TYPE_TX_ACK = 6,
+	FC_PACKET_TYPE_NMV_VECTOR = 7,
+	FC_PACKET_TYPE_NOTIFICATION = 8,
+	FC_PACKET_TYPE_TRIGGER_EX = 9,
+	FC_PACKET_TYPE_CAN = 10,
+	FC_PACKET_TYPE_CAN_ERROR = 11,
+};
+
+struct fc_packet {
+	__u32 type;
+	__u32 p_packet;
+	__u32 p_next_packet;
+} __packed;
+
+struct fc_info_packet {
+	__u32 current_cycle;
+	__u32 timestamp;
+	__u32 offset_rate_correction;
+	__u32 pta_ccf_count;
+	__u32 cc;
+} __packed;
+
+struct fc_flexray_frame {
+	__u32 header;
+	__u32 header_crc;
+	__u32 pdata;
+	__u32 channel;
+	__u32 frame_crc;
+	__u32 timestamp;
+	__u32 cc;
+} __packed;
+
+struct fc_error_packet {
+	__u32 flag;
+	__u32 timestamp;
+	__u32 cycle_count;
+	__u64 additional_info;
+	__u32 cc;
+	__u32 reserved;
+} __packed;
+
+struct fc_status_packet {
+	__u32 flag;
+	__u32 timestamp;
+	__u32 cycle_count;
+	__u32 additional_info;
+	__u32 cc;
+	__u32 reserved[2];
+} __packed;
+
+struct fc_tx_ack_packet {
+	__u32 bufferid;
+	__u32 timestamp;
+	__u32 cycle_count;
+	__u32 header;
+	__u32 header_crc;
+	__u32 pdata;
+	__u32 channel;
+	__u32 cc;
+} __packed;
+
+struct fc_nm_vector_packet {
+	__u32 timestamp;
+	__u32 cycle_count;
+	__u32 nmv_vector_length;
+	__u32 nmv_vector[3];
+	__u32 cc;
+	__u32 reserved;
+} __packed;
+
+struct fc_notification_packet {
+	__u32 timestamp;
+	__u32 sequence_count;
+	__u32 reserved;
+} __packed;
+
+struct fc_trigger_ex_info_packet {
+	__u32 condition;
+	__u32 timestamp;
+	__u32 sequence_count;
+	__u32 reserved1;
+	__u64 performance_counter;
+	__u32 edge;
+	__u32 trigger_line;
+	__u32 reserved[4];
+} __packed;
+
+struct fc_can_packet {
+	__u32 id;
+	__u32 timestamp;
+	__u32 flags;
+	__u32 reserved;
+	__u32 cc;
+	__u8 data[8];
+} __packed;
+
+struct fc_can_error_packet {
+	__u32 type;
+	__u32 state;
+	__u32 timestamp;
+	__u32 rx_error_counter;
+	__u32 tx_error_counter;
+	__u32 cc;
+	__u32 reserved[2];
+} __packed;
+
+enum fc_can_cc_state {
+	fc_can_state_unknown = 0,
+	fc_can_state_config,
+	fc_can_state_normalActive,
+	fc_can_state_warning,
+	fc_can_state_error_passive,
+	fc_can_state_bus_off,
+};
+
+enum fc_can_error_type {
+	fc_can_error_none = 0,
+	fc_can_error_stuff,
+	fc_can_error_form,
+	fc_can_error_acknowledge,
+	fc_can_error_bit1,
+	fc_can_error_bit0,
+	fc_can_error_crc,
+	fc_can_error_parity,
+};
+
+union fc_packet_types {
+	struct fc_info_packet		info_packet;
+	struct fc_flexray_frame		flexray_frame;
+	struct fc_error_packet		error_packet;
+	struct fc_status_packet		status_packet;
+	struct fc_tx_ack_packet		tx_ack_packet;
+	struct fc_nm_vector_packet	nm_vector_packet;
+	struct fc_notification_packet	notification_packet;
+	struct fc_trigger_ex_info_packet ex_info_packet;
+	struct fc_can_packet		can_packet;
+	struct fc_can_error_packet	can_error_packet;
+};
+
+struct fc_packet_buf {
+	struct  fc_packet	header;
+	union   fc_packet_types	packet;
+} __packed;
+
+u32 flexcard_parse_packet(struct fc_packet_buf *pb, u32 avail,
+			  struct flexcard_dma *dma);
+
+#endif /* __FLEXCARD_DMA_H */
diff --git a/drivers/dma/flexcard/parser.c b/drivers/dma/flexcard/parser.c
new file mode 100644
index 0000000..2450229
--- /dev/null
+++ b/drivers/dma/flexcard/parser.c
@@ -0,0 +1,227 @@
+/*
+ * Eberspächer Flexcard PMC II Carrier Board PCI Driver - packet parser/mux
+ *
+ * Copyright (c) 2014 - 2016, Linutronix GmbH
+ * Author: Benedikt Spranger <b.spranger@linutronix.de>
+ *         Holger Dengler <dengler@linutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/flexcard.h>
+#include "flexcard-dma.h"
+
+static LIST_HEAD(rx_cb_list);
+static DEFINE_SPINLOCK(rx_cb_lock);
+
+struct fc_rx_cb {
+	struct list_head list;
+	int (*rx_cb)(void *priv, void *data, size_t len);
+	int cc;
+	void *priv;
+};
+
+/**
+ * flexcard_register_rx_cb() - Registers a callback for received packages
+ * @cc:		communication controller id
+ * @priv:	pointer to private data of the cc
+ * @rx_cp:	pionter to the receive callback
+ *
+ * Registers a callback for a communication controller specific handling for
+ * received packages. The callback is called by the generic parser, if the
+ * communication controller id inside of the received package matches the cc
+ * of the callback owner.
+ *
+ * Return: 0 is returned on success and a negative errno code for failure.
+ */
+int flexcard_register_rx_cb(int cc, void *priv,
+			    int (*rx_cb)(void *priv, void *data, size_t len))
+{
+	unsigned long flags;
+	struct fc_rx_cb *cb, *next;
+
+	if (!rx_cb)
+		return -EINVAL;
+
+	cb = kmalloc(sizeof(*cb), GFP_KERNEL);
+	if (!cb)
+		return -ENOMEM;
+
+	cb->cc = cc;
+	cb->priv = priv;
+	cb->rx_cb = rx_cb;
+
+	spin_lock_irqsave(&rx_cb_lock, flags);
+	list_for_each_entry(next, &rx_cb_list, list)
+		if (next->cc == cc)
+			goto out;
+
+	list_add_tail(&cb->list, &rx_cb_list);
+	spin_unlock_irqrestore(&rx_cb_lock, flags);
+
+	return 0;
+out:
+	spin_unlock_irqrestore(&rx_cb_lock, flags);
+	kfree(cb);
+
+	return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(flexcard_register_rx_cb);
+
+/**
+ * flexcard_unregister_rx_cb() - Unregisters a callback for received packages
+ * @cc:		communication controller id
+ *
+ * Unregisters a callback for a communication controller specific handling for
+ * received packages.
+ *
+ * Return: 0 is returned on success and a negative errno code for failure.
+ */
+void flexcard_unregister_rx_cb(int cc)
+{
+	unsigned long flags;
+	struct fc_rx_cb *cur, *next;
+	int found = 0;
+
+	spin_lock_irqsave(&rx_cb_lock, flags);
+	list_for_each_entry_safe(cur, next, &rx_cb_list, list) {
+		if (cur->cc == cc) {
+			list_del(&cur->list);
+			kfree(cur);
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)
+		pr_err("no callback registered for cc %d\n", cc);
+
+	spin_unlock_irqrestore(&rx_cb_lock, flags);
+}
+EXPORT_SYMBOL_GPL(flexcard_unregister_rx_cb);
+
+static int flexcard_queue_rx(int cc, void *buf, size_t len)
+{
+	struct fc_rx_cb *next;
+	unsigned long flags;
+	int ret = -ENODEV;
+
+	spin_lock_irqsave(&rx_cb_lock, flags);
+	list_for_each_entry(next, &rx_cb_list, list)
+		if (next->cc == cc)
+			ret = next->rx_cb(next->priv, buf, len);
+	spin_unlock_irqrestore(&rx_cb_lock, flags);
+
+	return ret;
+}
+
+static u32 flexcard_get_packet_len(u32 header)
+{
+	u32 len;
+
+	/*
+	 * header contains the number of transmitted 16bit words in bits 30-16.
+	 * if the number is odd the DMA engine padded with zero to 32bit.
+	 * calculate the number of transmitted bytes.
+	 */
+
+	len = le32_to_cpu(header);
+
+	len >>= FLEXCARD_BUF_HEADER_LEN_SHIFT;
+	len &= FLEXCARD_BUF_HEADER_LEN_MASK;
+
+	len = roundup(len, 4);
+
+	return len;
+}
+
+/**
+ * selfsync_cc - adjust the cc number for self-sync packages
+ * @dma:	pointer to dma structure
+ * @cc:		package cc
+ *
+ * Some Flexcards has support for self-synci bus configurations. With this
+ * feature it is possible to get a synchronized bus configuration with a
+ * single card.
+ * Indication for a self-sync package is eray_nr == 1 and cc == 1. The
+ * packages are always handled by communication controller 0.
+ */
+static inline u32 selfsync_cc(struct flexcard_dma *dma, u32 cc)
+{
+		if ((dma->nr_eray == 1) && (cc == 1))
+			return 0;
+		return cc;
+}
+
+u32 flexcard_parse_packet(struct fc_packet_buf *pb, u32 avail,
+			  struct flexcard_dma *dma)
+{
+	u32 l, cc, len = sizeof(struct fc_packet);
+	union fc_packet_types *pt = &pb->packet;
+
+	switch (le32_to_cpu(pb->header.type)) {
+	case FC_PACKET_TYPE_INFO:
+		len += sizeof(struct fc_info_packet);
+		cc = pt->info_packet.cc;
+		break;
+	case FC_PACKET_TYPE_ERROR:
+		len += sizeof(struct fc_error_packet);
+		cc = pt->error_packet.cc;
+		break;
+	case FC_PACKET_TYPE_STATUS:
+		len += sizeof(struct fc_status_packet);
+		cc = selfsync_cc(dma, pt->status_packet.cc);
+		break;
+	case FC_PACKET_TYPE_NMV_VECTOR:
+		len += sizeof(struct fc_nm_vector_packet);
+		cc = pt->nm_vector_packet.cc;
+		break;
+	case FC_PACKET_TYPE_NOTIFICATION:
+		len += sizeof(struct fc_notification_packet);
+		cc = 0;
+		break;
+	case FC_PACKET_TYPE_TRIGGER_EX:
+		len += sizeof(struct fc_trigger_ex_info_packet);
+		cc = 0;
+		break;
+	case FC_PACKET_TYPE_CAN:
+		len += sizeof(struct fc_can_packet);
+		cc = FLEXCARD_CANIF_OFFSET + pt->can_packet.cc;
+		break;
+	case FC_PACKET_TYPE_CAN_ERROR:
+		len += sizeof(struct fc_can_error_packet);
+		cc = FLEXCARD_CANIF_OFFSET + pt->can_error_packet.cc;
+		break;
+	case FC_PACKET_TYPE_FLEXRAY_FRAME:
+		len += sizeof(struct fc_flexray_frame);
+		pt->flexray_frame.pdata = len;
+		l = flexcard_get_packet_len(pt->flexray_frame.header);
+		len += l;
+		cc = pt->flexray_frame.cc;
+		break;
+	case FC_PACKET_TYPE_TX_ACK:
+		len += sizeof(struct fc_tx_ack_packet);
+		pt->tx_ack_packet.pdata = len;
+		l = flexcard_get_packet_len(pt->tx_ack_packet.header);
+		len += l;
+		cc = selfsync_cc(dma, pt->tx_ack_packet.cc);
+		break;
+	case FC_PACKET_TYPE_TRIGGER:
+	default:
+		pr_debug("pkt->type = %08x\n", pb->header.type);
+		return 0;
+	}
+
+	if (len > avail)
+		return 0;
+
+	flexcard_queue_rx(cc, pb, len);
+
+	return len;
+}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 490b435..cb87c27 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -303,6 +303,7 @@ config MFD_FLEXCARD
 	tristate "Eberspaecher Flexcard PMC II Carrier Board"
 	select MFD_CORE
 	select IRQ_DOMAIN
+	select FLEXCARD_DMA
 	select FLEXCARD_MISC
 	select FLEXCARD_PCLOCK
 	depends on PCI
diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
index 819c6ef..eeabc9e 100644
--- a/include/linux/mfd/flexcard.h
+++ b/include/linux/mfd/flexcard.h
@@ -109,4 +109,8 @@ struct flexcard_device {
 int flexcard_setup_irq(struct pci_dev *pdev);
 void flexcard_remove_irq(struct pci_dev *pdev);
 
+int flexcard_register_rx_cb(int cc, void *priv,
+			    int (*rx_cb)(void *priv, void *data, size_t len));
+void flexcard_unregister_rx_cb(int cc);
+
 #endif /* _LINUX_FLEXCARD_H */
-- 
2.1.4

[toc] | [prev] | [next] | [standalone]


#1542475 — Re: [PATCH 12/12] dma: Flexcard DMA ringbuffer demux driver

FromVinod Koul <vinod.koul@intel.com>
Date2016-12-15 05:50 +0100
SubjectRe: [PATCH 12/12] dma: Flexcard DMA ringbuffer demux driver
Message-ID<sOw9r-1fR-1@gated-at.bofh.it>
In reply to#1541608
On Wed, Dec 14, 2016 at 01:11:53AM +0100, Holger Dengler wrote:
> The Flexcard interface design split packet receive and transmit. All
> received packets and card status information are multiplexed with a
> Flexcard specific protocol and handled through a DMA capable ringbuffer.
> The TX path has to poke each available component separate.
> 
> Add a Flexcard DMA ringbuffer driver and packet demultiplexer.

so the dma driver should only provide service and not do demuxing...

> +config FLEXCARD_DMA
> +	tristate "DMA support for Eberspaecher Flexcard PMC II Carrier Board"
> +	depends on MFD_FLEXCARD
> +	help
> +	  The Eberspaecher Flexcard PMC (PCI Mezzanine Card) II carrier
> +	  board support one DMA capable receive ringbuffer for all devices.
> +	  A card specific protocol is used to multiplex the received packets
> +	  through the ringbuffer. Enable DMA and Packet parser.
> +

This file is sorted alphabetically, so please add it it relavant place

> +#define DMA_TOTAL_BUF_SIZE		(2*FLEXCARD_DMA_BUF_SIZE)

space around * pls

> +#define FLEXCARD_DMA_BUF_SIZE		0x200000
> +#define FLEXCARD_DMA_BUF_MASK		(FLEXCARD_DMA_BUF_SIZE - 1)
> +
> +#define FLEXCARD_DMA_CTRL_DMA_ENA	(1 << 0)
> +#define FLEXCARD_DMA_CTRL_MAN_ENA	(1 << 1)
> +#define FLEXCARD_DMA_CTRL_STOP_REQ	(1 << 16)
> +#define FLEXCARD_DMA_CTRL_DMA_IDLE	(1 << 17)
> +#define FLEXCARD_DMA_CTRL_RST_DMA	(1 << 31)

BIT() and friends please

> +
> +#define FLEXCARD_DMA_STAT_BUSY		(1 << 15)
> +#define FLEXCARD_DMA_STAT_OFL		(1 << 31)
> +
> +#define FLEXCARD_MAX_PAKET_SIZE		0x200
> +
> +#define FLEXCARD_BUF_HEADER_LEN_SHIFT	15
> +#define FLEXCARD_BUF_HEADER_LEN_MASK	0xfe
> +
> +#define FLEXCARD_CANIF_OFFSET		0x20

Okay I have skipped over the parser and other stuff and still looking for
the dmaengine APIs. 

This driver _doesn't_ do that, and am not sure why.

Anyway, if this driver doesnt need dmaengine APIs it doesnt belong in
drivers/dma/. Otherwise please port to dmanegine APIs, possibly use parser
as a client. You cna use virt-channels as well for managing the transfers.

So I am not considering this submission

Thanks
-- 
~Vinod

[toc] | [prev] | [next] | [standalone]


#1544453 — Re: [PATCH 12/12] dma: Flexcard DMA ringbuffer demux driver

FromHolger Dengler <dengler@linutronix.de>
Date2016-12-19 12:00 +0100
SubjectRe: [PATCH 12/12] dma: Flexcard DMA ringbuffer demux driver
Message-ID<sQ3PH-6CU-17@gated-at.bofh.it>
In reply to#1542475

[Multipart message — attachments visible in raw view] — view raw

On 12/15/2016 05:38 AM, Vinod Koul wrote:
> On Wed, Dec 14, 2016 at 01:11:53AM +0100, Holger Dengler wrote:
>> The Flexcard interface design split packet receive and transmit. All
>> received packets and card status information are multiplexed with a
>> Flexcard specific protocol and handled through a DMA capable ringbuffer.
>> The TX path has to poke each available component separate.
>>
>> Add a Flexcard DMA ringbuffer driver and packet demultiplexer.
> 
> so the dma driver should only provide service and not do demuxing...

The Flexcard can be equipped with multiple functional modules (so called Tinys). Unfortunately, the RX traffic of all Tinys is handled by the base card in a single DMA-ringbuffer. No separate channels, no scatter-gather-lists. So RX-demuxing must be done by one single instance per base card. The TX-path is _not_ handled via DMA, the data goes directly to the Tiny registers.

>> +#define FLEXCARD_DMA_STAT_BUSY		(1 << 15)
>> +#define FLEXCARD_DMA_STAT_OFL		(1 << 31)
>> +
>> +#define FLEXCARD_MAX_PAKET_SIZE		0x200
>> +
>> +#define FLEXCARD_BUF_HEADER_LEN_SHIFT	15
>> +#define FLEXCARD_BUF_HEADER_LEN_MASK	0xfe
>> +
>> +#define FLEXCARD_CANIF_OFFSET		0x20
> 
> Okay I have skipped over the parser and other stuff and still looking for
> the dmaengine APIs. 
> 
> This driver _doesn't_ do that, and am not sure why.

The main reason, why we do not used the dmaengine interfaces, is, that the Flexcard DMA engine is not as flexible as normal DMA engines are. It is only used for the receive path, it does not support separate channels per Tiny and it uses a single ring-buffer instead of scatter-gather-lists. If we would use the dmaengine interfaces, we would end up with a solution, that accepts only one client per card, and the client must always be the parser (because of the demuxing). Therefore, I do not see any advantage in using the dmaengine interfaces.

> Anyway, if this driver doesnt need dmaengine APIs it doesnt belong in
> drivers/dma/. Otherwise please port to dmanegine APIs, possibly use parser
> as a client. You cna use virt-channels as well for managing the transfers.

Ok, I can follow your argumentation, that the driver for the Flexcard "DMA" does not belong to drivers/dma. In our second post [1], we had it in drivers/mfd, but Lee mentioned, that it is not a mfd driver and asked us to move it to drivers/dma [2]. But if it is neither a mfd nor a dmaengine driver, what kind of driver is it? What is the right place for this driver? (Maybe the naming of the driver is too confusing. Although the Flexcard use DMA (from a technically point of view), this function is more a RX-demux-engine...)

@Lee: 
with Vinods comments, the information above and (optionally) a renaming, do you see any possibility to re-include it in drivers/mfd?

[1] http://www.spinics.net/lists/kernel/msg1954282.html
[2] http://www.spinics.net/lists/kernel/msg1957525.html

> 
> So I am not considering this submission
> 
> Thanks
> 
-- 
Gruß,
Holger Dengler
--
phone: +49 7556 25 999 14; fax: +49 7556 25 999 99

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web