lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 25 Mar 2015 10:51:58 +0100
From:	Holger Dengler <dengler@...utronix.de>
To:	linux-kernel@...r.kernel.org
Cc:	Peter Mahler <mahler@...ug.com>, Juergen Bubeck <bubeck@...ug.com>,
	Benedikt Spranger <b.spranger@...utronix.de>,
	Holger Dengler <dengler@...utronix.de>,
	Samuel Ortiz <sameo@...ux.intel.com>,
	Lee Jones <lee.jones@...aro.org>
Subject: [PATCH 09/11] mfd: flexcard: add DMA ringbuffer demux driver

From: Benedikt Spranger <b.spranger@...utronix.de>

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: Holger Dengler <dengler@...utronix.de>
Signed-off-by: Benedikt Spranger <b.spranger@...utronix.de>
cc: Samuel Ortiz <sameo@...ux.intel.com>
cc: Lee Jones <lee.jones@...aro.org>
---
 drivers/mfd/Kconfig                 |   9 ++
 drivers/mfd/flexcard/Makefile       |   3 +
 drivers/mfd/flexcard/dma.c          | 286 ++++++++++++++++++++++++++++++++++++
 drivers/mfd/flexcard/flexcard-dma.h | 207 ++++++++++++++++++++++++++
 drivers/mfd/flexcard/parser.c       | 193 ++++++++++++++++++++++++
 include/linux/mfd/flexcard.h        |   5 +
 6 files changed, 703 insertions(+)
 create mode 100644 drivers/mfd/flexcard/dma.c
 create mode 100644 drivers/mfd/flexcard/flexcard-dma.h
 create mode 100644 drivers/mfd/flexcard/parser.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f624b7f..cd798a6 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -228,6 +228,15 @@ config MFD_FLEXCARD
 	  can take up to 4 exchangeable physical layer boards for
 	  CAN, FlexRay or Ethernet.
 
+config MFD_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 MFD_MC13XXX
 	tristate
 	depends on (SPI_MASTER || I2C)
diff --git a/drivers/mfd/flexcard/Makefile b/drivers/mfd/flexcard/Makefile
index 4f72c9c..695ba44 100644
--- a/drivers/mfd/flexcard/Makefile
+++ b/drivers/mfd/flexcard/Makefile
@@ -1,2 +1,5 @@
 obj-$(CONFIG_MFD_FLEXCARD)	+= flexcard.o
 flexcard-objs			:= core.o attr.o irq.o
+
+obj-$(CONFIG_MFD_FLEXCARD_DMA)	+= flexcard-dma.o
+flexcard-dma-objs		:= dma.o parser.o
diff --git a/drivers/mfd/flexcard/dma.c b/drivers/mfd/flexcard/dma.c
new file mode 100644
index 0000000..ed4e2ea
--- /dev/null
+++ b/drivers/mfd/flexcard/dma.c
@@ -0,0 +1,286 @@
+/*
+ * Eberspaecher Flexcard PMC II Carrier Board PCI Driver - DMA controller
+ *
+ * Copyright (c) 2014,2015 Linutronix GmbH
+ * Author: Holger Dengler
+ *         Benedikt Spranger
+ *
+ * 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/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/flexcard.h>
+
+#include "flexcard-dma.h"
+
+static int flexcard_dma_stop(struct flexcard_dma *dma)
+{
+	void *dma_ctrl = &dma->reg->dma_ctrl;
+	void *dma_stat = &dma->reg->dma_stat;
+	int retry = 200;
+
+	writel(FLEXCARD_DMA_CTRL_STOP_REQ, dma_ctrl);
+
+	while (!(readl(dma_ctrl) & FLEXCARD_DMA_CTRL_DMA_IDLE) && retry--)
+		udelay(1);
+	if (!retry)
+		return -EBUSY;
+
+	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)
+{
+	void *dma_ctrl = &dma->reg->dma_ctrl;
+	int retry = 500;
+
+	writel(FLEXCARD_DMA_CTRL_RST_DMA, dma_ctrl);
+
+	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)
+		goto out;
+
+	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);
+out:
+	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) {
+		u32 *p = dma->buf + 2*FLEXCARD_DMA_BUF_SIZE - 4;
+		*p = dma->rptr = rptr;
+		writel(rptr, &dma->reg->dma_rptr);
+	} else {
+		/* This should not happen. Or can it ? */
+		dev_err(&pdev->dev, "rptr unchanged\n");
+	}
+
+	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 = -ENOMEM;
+
+	cell = mfd_get_cell(pdev);
+	if (!cell)
+		return -ENODEV;
+
+	dma = devm_kzalloc(&pdev->dev, sizeof(*dma), GFP_KERNEL);
+	if (!dma)
+		goto out;
+
+	platform_set_drvdata(pdev, dma);
+
+	dma->buf = dma_alloc_coherent(&pdev->dev, 2*FLEXCARD_DMA_BUF_SIZE,
+				      &dma->phys, GFP_KERNEL);
+	if (!dma->buf) {
+		dev_err(&pdev->dev, "could not allocate DMA memory\n");
+		goto out;
+	}
+
+	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, 2*FLEXCARD_DMA_BUF_SIZE,
+			  dma->buf, dma->phys);
+out:
+	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");
+		goto out;
+	}
+
+	dma_free_coherent(&pdev->dev, 2*FLEXCARD_DMA_BUF_SIZE,
+			  dma->buf, dma->phys);
+
+out:
+	return ret;
+}
+
+static struct platform_driver flexcard_dma_driver = {
+	.probe		= flexcard_dma_probe,
+	.remove		= flexcard_dma_remove,
+	.driver		= {
+		.name   = "flexcard-dma",
+	}
+};
+
+static int __init flexcard_dma_init(void)
+{
+	return platform_driver_register(&flexcard_dma_driver);
+}
+
+static void __exit flexcard_dma_exit(void)
+{
+	platform_driver_unregister(&flexcard_dma_driver);
+}
+
+module_init(flexcard_dma_init);
+module_exit(flexcard_dma_exit);
+
+MODULE_AUTHOR("Holger Dengler <dengler@...utronix.de>");
+MODULE_AUTHOR("Benedikt Spranger <b.spranger@...utronix.de>");
+MODULE_DESCRIPTION("Eberspaecher Flexcard PMC II DMA Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:flexcard-dma");
diff --git a/drivers/mfd/flexcard/flexcard-dma.h b/drivers/mfd/flexcard/flexcard-dma.h
new file mode 100644
index 0000000..7de1b23
--- /dev/null
+++ b/drivers/mfd/flexcard/flexcard-dma.h
@@ -0,0 +1,207 @@
+#ifndef __FLEXCARD_H
+#define  __FLEXCARD_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 __iomem {
+	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_H */
diff --git a/drivers/mfd/flexcard/parser.c b/drivers/mfd/flexcard/parser.c
new file mode 100644
index 0000000..83a6e8e
--- /dev/null
+++ b/drivers/mfd/flexcard/parser.c
@@ -0,0 +1,193 @@
+/*
+ * Eberspaecher Flexcard PMC II Carrier Board PCI Driver - packet parser/mux
+ *
+ * Copyright (c) 2014,2015 Linutronix GmbH
+ * Author: Holger Dengler
+ *         Benedikt Spranger
+ *
+ * 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 "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;
+};
+
+int flexcard_register_rx_pkt(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_ATOMIC);
+	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_pkt);
+
+void flexcard_unregister_rx_pkt(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;
+		}
+	}
+
+	WARN_ON(!found);
+
+	spin_unlock_irqrestore(&rx_cb_lock, flags);
+}
+EXPORT_SYMBOL_GPL(flexcard_unregister_rx_pkt);
+
+static int flexcard_send_pkt(int cc, void *buf, size_t len)
+{
+	struct fc_rx_cb *next;
+	int ret = -ENODEV;
+
+	spin_lock(&rx_cb_lock);
+	list_for_each_entry(next, &rx_cb_list, list)
+		if (next->cc == cc)
+			ret = next->rx_cb(next->priv, buf, len);
+	spin_unlock(&rx_cb_lock);
+
+	return ret;
+}
+
+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;
+}
+EXPORT_SYMBOL_GPL(flexcard_get_packet_len);
+
+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 = pt->status_packet.cc;
+
+		/* self sync status */
+		if ((dma->nr_eray == 1) && (cc == 1))
+			cc = 0;
+		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 = pt->tx_ack_packet.cc;
+
+		/* self sync tx ack */
+		if ((dma->nr_eray == 1) && (cc == 1))
+			cc = 0;
+		break;
+	case fc_packet_type_trigger:
+	default:
+		pr_debug("pkt->type = %08x\n", pb->header.type);
+		return 0;
+	}
+
+	if (len > avail)
+		return 0;
+
+	flexcard_send_pkt(cc, pb, len);
+
+	return len;
+}
diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
index f9b0962..964d78c 100644
--- a/include/linux/mfd/flexcard.h
+++ b/include/linux/mfd/flexcard.h
@@ -62,4 +62,9 @@ enum flexcard_cell_id {
 #define FLEXCARD_DMA_IRQ_TI		2
 #define FLEXCARD_DMA_IRQ_CBL		3
 
+int flexcard_register_rx_pkt(int cc, void *priv,
+			     int (*rx_cb)(void *priv, void *data, size_t len));
+void flexcard_unregister_rx_pkt(int cc);
+u32 flexcard_get_packet_len(u32 header);
+
 #endif /* FLEXCARD_H */
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ