All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-02-24 16:48 ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-24 16:48 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree; +Cc: Stathis Voukelatos

This patch adds support for the Ethernet Packet Sniffer H/W module
developed by Linn Products Ltd and found in the IMG Pistachio SoC.
The module allows Ethernet packets to be parsed, matched against
a user-defined pattern and timestamped. It sits between a 100M
Ethernet MAC and PHY and is completely passive with respect to
Ethernet frames.

Selected packet bytes from matched packets and timestamp values are
returned through a H/W FIFO. Timestamps are provided to the module
through an externally generated Gray-encoded counter.

The command string for packet matching is stored in module RAM
and consists of a sequence of 16-bit entries. Each entry includes
an 8-bit command code and and 8-bit data value. Valid command
codes are:
0 - Don't care
1 - Match: packet data must match command string byte
2 - Copy: packet data will be copied to FIFO
3 - Match/Stamp: if packet data matches string byte, a timestamp
                 is copied into the FIFO
4 - Copy/Done: packet data will be copied into the FIFO.
               This command terminates the command string.

The driver consists of two modules:
- Core: it provides a common framework for managing backend packet
        sniffer implementations. Each backend channel is registered
        by the core as a netdev, which can be accessed from user
        space through AF_PACKET sockets. 

- Ethernet Packet Sniffer backend: provides the driver for the
        Linn Ethernet Packet Sniffer H/W modules.

The split between a core and backend modules allows for other
implementations to be added in the future apart of the Ethernet
packet sniffer presented in this patch set.

Changelog:

v4:
* More detailed documentation on driver usage (in snf_core.c) and 
  H/W operation (in platform.c)
* Some source file renaming in the core module.
* Rebased against linux-net-next

v3:
* Code moved into vendor specific directory
* Device tree binding updated and streamlined. Cyclecounter params
  are now calculated dynamically.

v2:
* Complete redesign of core framework to use netdev instead of 
the generic netlink framework
* Updated device tree binding
* A number of minor code improvements suggested by code review

Stathis Voukelatos (3):
  Linn Ethernet packet sniffer: device tree binding and vendor prefix
  Linn packet sniffer core framework
  Linn Ethernet packet sniffer driver

 .../bindings/net/linn-ether-packet-sniffer.txt     |  39 ++
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 MAINTAINERS                                        |   6 +
 drivers/net/ethernet/Kconfig                       |   1 +
 drivers/net/ethernet/Makefile                      |   1 +
 drivers/net/ethernet/linn/Kconfig                  |  36 ++
 drivers/net/ethernet/linn/Makefile                 |  20 +
 .../linn/pkt-sniffer/backends/ether/Makefile       |  20 +
 .../linn/pkt-sniffer/backends/ether/channel.c      | 444 +++++++++++++++++++++
 .../linn/pkt-sniffer/backends/ether/channel.h      |  80 ++++
 .../ethernet/linn/pkt-sniffer/backends/ether/hw.h  |  46 +++
 .../linn/pkt-sniffer/backends/ether/platform.c     | 318 +++++++++++++++
 .../net/ethernet/linn/pkt-sniffer/core/Makefile    |  19 +
 .../net/ethernet/linn/pkt-sniffer/core/snf_core.c  | 344 ++++++++++++++++
 .../net/ethernet/linn/pkt-sniffer/core/snf_core.h  |  60 +++
 15 files changed, 1435 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt
 create mode 100644 drivers/net/ethernet/linn/Kconfig
 create mode 100644 drivers/net/ethernet/linn/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-02-24 16:48 ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-24 16:48 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree; +Cc: Stathis Voukelatos

This patch adds support for the Ethernet Packet Sniffer H/W module
developed by Linn Products Ltd and found in the IMG Pistachio SoC.
The module allows Ethernet packets to be parsed, matched against
a user-defined pattern and timestamped. It sits between a 100M
Ethernet MAC and PHY and is completely passive with respect to
Ethernet frames.

Selected packet bytes from matched packets and timestamp values are
returned through a H/W FIFO. Timestamps are provided to the module
through an externally generated Gray-encoded counter.

The command string for packet matching is stored in module RAM
and consists of a sequence of 16-bit entries. Each entry includes
an 8-bit command code and and 8-bit data value. Valid command
codes are:
0 - Don't care
1 - Match: packet data must match command string byte
2 - Copy: packet data will be copied to FIFO
3 - Match/Stamp: if packet data matches string byte, a timestamp
                 is copied into the FIFO
4 - Copy/Done: packet data will be copied into the FIFO.
               This command terminates the command string.

The driver consists of two modules:
- Core: it provides a common framework for managing backend packet
        sniffer implementations. Each backend channel is registered
        by the core as a netdev, which can be accessed from user
        space through AF_PACKET sockets. 

- Ethernet Packet Sniffer backend: provides the driver for the
        Linn Ethernet Packet Sniffer H/W modules.

The split between a core and backend modules allows for other
implementations to be added in the future apart of the Ethernet
packet sniffer presented in this patch set.

Changelog:

v4:
* More detailed documentation on driver usage (in snf_core.c) and 
  H/W operation (in platform.c)
* Some source file renaming in the core module.
* Rebased against linux-net-next

v3:
* Code moved into vendor specific directory
* Device tree binding updated and streamlined. Cyclecounter params
  are now calculated dynamically.

v2:
* Complete redesign of core framework to use netdev instead of 
the generic netlink framework
* Updated device tree binding
* A number of minor code improvements suggested by code review

Stathis Voukelatos (3):
  Linn Ethernet packet sniffer: device tree binding and vendor prefix
  Linn packet sniffer core framework
  Linn Ethernet packet sniffer driver

 .../bindings/net/linn-ether-packet-sniffer.txt     |  39 ++
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 MAINTAINERS                                        |   6 +
 drivers/net/ethernet/Kconfig                       |   1 +
 drivers/net/ethernet/Makefile                      |   1 +
 drivers/net/ethernet/linn/Kconfig                  |  36 ++
 drivers/net/ethernet/linn/Makefile                 |  20 +
 .../linn/pkt-sniffer/backends/ether/Makefile       |  20 +
 .../linn/pkt-sniffer/backends/ether/channel.c      | 444 +++++++++++++++++++++
 .../linn/pkt-sniffer/backends/ether/channel.h      |  80 ++++
 .../ethernet/linn/pkt-sniffer/backends/ether/hw.h  |  46 +++
 .../linn/pkt-sniffer/backends/ether/platform.c     | 318 +++++++++++++++
 .../net/ethernet/linn/pkt-sniffer/core/Makefile    |  19 +
 .../net/ethernet/linn/pkt-sniffer/core/snf_core.c  | 344 ++++++++++++++++
 .../net/ethernet/linn/pkt-sniffer/core/snf_core.h  |  60 +++
 15 files changed, 1435 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt
 create mode 100644 drivers/net/ethernet/linn/Kconfig
 create mode 100644 drivers/net/ethernet/linn/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH net-next v4 1/3] Linn Ethernet packet sniffer: device tree binding and vendor prefix
  2015-02-24 16:48 ` Stathis Voukelatos
@ 2015-02-24 16:48   ` Stathis Voukelatos
  -1 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-24 16:48 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree; +Cc: Stathis Voukelatos

Signed-off-by: Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
---
 .../bindings/net/linn-ether-packet-sniffer.txt     | 39 ++++++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 2 files changed, 40 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt

diff --git a/Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt b/Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt
new file mode 100644
index 0000000..66bfc48
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt
@@ -0,0 +1,39 @@
+* Linn Products Ethernet Packet Sniffer
+The module allows Ethernet packets to be parsed, matched against
+a user-defined pattern and timestamped. It sits between a 100M
+Ethernet MAC and PHY and is completely passive with respect to
+Ethernet frames.
+Matched packet bytes and timestamp values are returned through a
+FIFO. Timestamps are provided to the module through an externally
+generated Gray-encoded counter.
+
+Required properties:
+- compatible : must be "linn,eth-packet-sniffer"
+- reg : a list of physical address and size pairs corresponding to
+	each entry in 'reg-names'
+- reg-names : must contain:
+		"regs"   : control registers
+		"tx-ram" : TX command string memory
+		"rx-ram" : RX command string memory
+- interrupts : sniffer interrupt specifier
+- clocks : list of clocks corresponding to each entry in 'clock-names'
+- clock-names : must contain:
+		"sys"    : system clock for the peripheral
+		"tstamp" : timestamp counter clock
+- fifo-block-words : number of words in one data FIFO entry
+- tstamp-bits : width in bits of the timestamp counter
+
+Example:
+
+sniffer@1814a000 {
+	compatible = "linn,eth-sniffer";
+	reg = <0x1814a000 0x100>, <0x1814a400 0x400>,
+	      <0x1814a800 0x400>;
+	reg-names = "regs", "tx-ram", "rx-ram";
+	interrupts = <GIC_SHARED 58 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&cr_periph SYS_CLK_ENET>,
+		 <&clk_core CLK_AUDIO>;
+	clock-names = "sys", "tstamp";
+	fifo-block-words = <4>;
+	tstamp-bits = <30>;
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 389ca13..f685707 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -102,6 +102,7 @@ lacie	LaCie
 lantiq	Lantiq Semiconductor
 lenovo	Lenovo Group Ltd.
 lg	LG Corporation
+linn	Linn Products Ltd.
 linux	Linux-specific binding
 lsi	LSI Corp. (LSI Logic)
 lltc	Linear Technology Corporation
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH net-next v4 1/3] Linn Ethernet packet sniffer: device tree binding and vendor prefix
@ 2015-02-24 16:48   ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-24 16:48 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree; +Cc: Stathis Voukelatos

Signed-off-by: Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
---
 .../bindings/net/linn-ether-packet-sniffer.txt     | 39 ++++++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 2 files changed, 40 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt

diff --git a/Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt b/Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt
new file mode 100644
index 0000000..66bfc48
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt
@@ -0,0 +1,39 @@
+* Linn Products Ethernet Packet Sniffer
+The module allows Ethernet packets to be parsed, matched against
+a user-defined pattern and timestamped. It sits between a 100M
+Ethernet MAC and PHY and is completely passive with respect to
+Ethernet frames.
+Matched packet bytes and timestamp values are returned through a
+FIFO. Timestamps are provided to the module through an externally
+generated Gray-encoded counter.
+
+Required properties:
+- compatible : must be "linn,eth-packet-sniffer"
+- reg : a list of physical address and size pairs corresponding to
+	each entry in 'reg-names'
+- reg-names : must contain:
+		"regs"   : control registers
+		"tx-ram" : TX command string memory
+		"rx-ram" : RX command string memory
+- interrupts : sniffer interrupt specifier
+- clocks : list of clocks corresponding to each entry in 'clock-names'
+- clock-names : must contain:
+		"sys"    : system clock for the peripheral
+		"tstamp" : timestamp counter clock
+- fifo-block-words : number of words in one data FIFO entry
+- tstamp-bits : width in bits of the timestamp counter
+
+Example:
+
+sniffer@1814a000 {
+	compatible = "linn,eth-sniffer";
+	reg = <0x1814a000 0x100>, <0x1814a400 0x400>,
+	      <0x1814a800 0x400>;
+	reg-names = "regs", "tx-ram", "rx-ram";
+	interrupts = <GIC_SHARED 58 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&cr_periph SYS_CLK_ENET>,
+		 <&clk_core CLK_AUDIO>;
+	clock-names = "sys", "tstamp";
+	fifo-block-words = <4>;
+	tstamp-bits = <30>;
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 389ca13..f685707 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -102,6 +102,7 @@ lacie	LaCie
 lantiq	Lantiq Semiconductor
 lenovo	Lenovo Group Ltd.
 lg	LG Corporation
+linn	Linn Products Ltd.
 linux	Linux-specific binding
 lsi	LSI Corp. (LSI Logic)
 lltc	Linear Technology Corporation
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH net-next v4 2/3] Linn packet sniffer core framework
  2015-02-24 16:48 ` Stathis Voukelatos
@ 2015-02-24 16:48   ` Stathis Voukelatos
  -1 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-24 16:48 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree; +Cc: Stathis Voukelatos

The framework registers each backend sniffer channel as a netdev,
which can be accessed from user space through a raw packet socket.
Packets received from user space are treated as a command string
configuration. Each match event from the backend driver will
generate a packet with the matching bytes plus an optional
timestamp, if configured by the command string.

Signed-off-by: Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
---
 MAINTAINERS                                        |   6 +
 drivers/net/ethernet/Kconfig                       |   1 +
 drivers/net/ethernet/Makefile                      |   1 +
 drivers/net/ethernet/linn/Kconfig                  |  25 ++
 drivers/net/ethernet/linn/Makefile                 |  19 ++
 .../net/ethernet/linn/pkt-sniffer/core/Makefile    |  19 ++
 .../net/ethernet/linn/pkt-sniffer/core/snf_core.c  | 344 +++++++++++++++++++++
 .../net/ethernet/linn/pkt-sniffer/core/snf_core.h  |  60 ++++
 8 files changed, 475 insertions(+)
 create mode 100644 drivers/net/ethernet/linn/Kconfig
 create mode 100644 drivers/net/ethernet/linn/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 0597c5b..6186c0c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5828,6 +5828,12 @@ M:	Sasha Levin <sasha.levin@oracle.com>
 S:	Maintained
 F:	tools/lib/lockdep/
 
+LINN PACKET SNIFFER DRIVER
+M: Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+S: Maintained
+F: drivers/net/ethernet/linn/
+F: Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt
+
 LINUX FOR IBM pSERIES (RS/6000)
 M:	Paul Mackerras <paulus@au.ibm.com>
 W:	http://www.ibm.com/linux/ltc/projects/ppc
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index eadcb05..ee4b3ed 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -103,6 +103,7 @@ config LANTIQ_ETOP
 	---help---
 	  Support for the MII0 inside the Lantiq SoC
 
+source "drivers/net/ethernet/linn/Kconfig"
 source "drivers/net/ethernet/marvell/Kconfig"
 source "drivers/net/ethernet/mellanox/Kconfig"
 source "drivers/net/ethernet/micrel/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 1367afc..f8071d3 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_NET_VENDOR_HP) += hp/
 obj-$(CONFIG_NET_VENDOR_IBM) += ibm/
 obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
 obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
+obj-$(CONFIG_NET_VENDOR_LINN) += linn/
 obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/
 obj-$(CONFIG_IP1000) += icplus/
 obj-$(CONFIG_JME) += jme.o
diff --git a/drivers/net/ethernet/linn/Kconfig b/drivers/net/ethernet/linn/Kconfig
new file mode 100644
index 0000000..6654f4e
--- /dev/null
+++ b/drivers/net/ethernet/linn/Kconfig
@@ -0,0 +1,25 @@
+#
+# Linn device configuration
+#
+
+config NET_VENDOR_LINN
+	bool "Linn devices"
+	---help---
+	  Say Y to add support for Linn Products devices.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about Linn devices. If you say Y, you will be asked for
+	  your specific device in the following questions.
+
+if NET_VENDOR_LINN
+
+menuconfig PKT_SNIFFER
+    tristate "Packet sniffer support"
+    ---help---
+    Say Y to add support for the packet sniffer driver framework.
+
+    The core driver can also be built as a module. If so, the module
+    will be called snf_core.
+
+endif # NET_VENDOR_LINN
diff --git a/drivers/net/ethernet/linn/Makefile b/drivers/net/ethernet/linn/Makefile
new file mode 100644
index 0000000..f3338f3
--- /dev/null
+++ b/drivers/net/ethernet/linn/Makefile
@@ -0,0 +1,19 @@
+###############################################################################
+# Makefile for the Linn Products device drivers
+#
+# Copyright (C) 2015 Linn Products Ltd
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# Written by:
+# Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+###############################################################################
+
+obj-$(CONFIG_PKT_SNIFFER) += pkt-sniffer/core/
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/core/Makefile b/drivers/net/ethernet/linn/pkt-sniffer/core/Makefile
new file mode 100644
index 0000000..4dc8f11
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/core/Makefile
@@ -0,0 +1,19 @@
+###############################################################################
+# Makefile for the Linn packet sniffer framework driver
+#
+# Copyright (C) 2015 Linn Products Ltd
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# Written by:
+# Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+###############################################################################
+
+obj-$(CONFIG_PKT_SNIFFER) += snf_core.o
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c b/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c
new file mode 100644
index 0000000..9490943
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c
@@ -0,0 +1,344 @@
+/*
+ * The Linn packet sniffer allows incoming or outgoing data packets
+ * to be parsed, matched against a user-defined data pattern and
+ * timestamped.
+ *
+ * Packet filtering is driven by a user-supplied command string
+ * which consists of a series of interleaved command and data bytes.
+ * ie. the command string has the following format:
+ *  --------------------------------
+ *  | CMD | DATA | CMD | DATA | ....
+ *  --------------------------------
+ * The supported commands and their function is documented in the
+ * corresponding backend driver.
+ * Data returned to the user for each matched packet include selected
+ * data bytes from the packet and optionally a timestamp.
+ *
+ * This module is the packet sniffer core driver that handles
+ * the interface between the H/W backend modules and user space:
+ *
+ * - Each backend sniffer channel is registered as a netdev, eg. Ethernet
+ *   TX and RX are two different channels.
+ *
+ * - Access from user space is through AF_PACKET sockets bound to
+ *   the netdev
+ *
+ * - User space supplies the command string by writing a packet to a socket.
+ *   The packet will contain interleaved commands and data values as
+ *   shown above.
+ *
+ * - Data from each packet match event are also returned through an AF_PACKET
+ *   socket. Timestamps use the existing kernel timestamping framework,
+ *   ie. they are returned to the user through a socket control message
+ *   (ancillary data).
+ *
+ * Example usage:
+ *    - Open a socket
+ *         fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ *    - Bind it to the netdev
+ *         strcpy(ifr.ifr_name, "snfethrx0");
+ *         ioctl(fd, SIOCGIFINDEX, &ifr);
+ *         ll.sll_family = AF_PACKET;
+ *         ll.sll_ifindex = ifr.ifr_ifindex;
+ *         bind(fd, (struct sockaddr *) &ll, sizeof(ll));
+ *    - Enable timestamping at the driver and socket level
+ *         ioctl(fd, SIOCSHWTSTAMP, &ifr);
+ *         opt = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE;
+ *         setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &opt, sizeof(opt));
+ *    - Configure a command string
+ *         char buf[4] = {0x03, 0xAB, 0x4, 0x00};
+ *         write(fd, buf, 4);
+ *    - Wait for a packet match
+ *         select(fd+1, &rfds, NULL, NULL, NULL);
+ *    - Read data
+ *         recvmsg(fd, &msg, 0);
+ *    - Timestamp will be available through a control message
+ *	   cmsg = CMSG_FIRSTHDR(&msg);
+ *         if (cmsg->cmsg_type == SO_TIMESTAMPING)
+ *		struct timespec *scmt = CMSG_DATA(cmsg);
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/net_tstamp.h>
+#include <linux/if_arp.h>
+#include <linux/spinlock.h>
+#include "snf_core.h"
+
+struct snf_ndev_state {
+	struct snf_chan *chan;
+	bool rx_tstamp_enabled;
+	spinlock_t lock;
+};
+
+static int hw_timestamp_set(struct net_device *dev, struct ifreq *ifr)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	struct hwtstamp_config tconf;
+
+	if (copy_from_user(&tconf, ifr->ifr_data, sizeof(tconf)))
+		return -EFAULT;
+
+	/* No TX timestamping supported.
+	 * This interface only receives packets from the sniffer backend
+	 */
+	if (tconf.tx_type != HWTSTAMP_TX_OFF)
+		return -ERANGE;
+
+	if (tconf.rx_filter != HWTSTAMP_FILTER_NONE) {
+		/* If timestamping is not enabled in the command string then
+		 * we cannot return any RX timestamps
+		 */
+		if (!priv->chan->ts_enabled(priv->chan))
+			return -ERANGE;
+		priv->rx_tstamp_enabled = true;
+		tconf.rx_filter = HWTSTAMP_FILTER_ALL;
+	} else {
+		priv->rx_tstamp_enabled = false;
+	}
+
+	return copy_to_user(ifr->ifr_data, &tconf, sizeof(tconf)) ? -EFAULT : 0;
+}
+
+static int hw_timestamp_get(struct net_device *dev, struct ifreq *ifr)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	struct hwtstamp_config tconf;
+
+	memset(&tconf, 0, sizeof(tconf));
+	tconf.tx_type = HWTSTAMP_TX_OFF;
+	/* We also need to check here that the current command string
+	 * will cause timestamps to be generated
+	 */
+	tconf.rx_filter = (priv->rx_tstamp_enabled &&
+			   priv->chan->ts_enabled(priv->chan)) ?
+			   HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
+
+	return copy_to_user(ifr->ifr_data, &tconf, sizeof(tconf)) ? -EFAULT : 0;
+}
+
+static int snf_init(struct net_device *dev)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+
+	/* Two bytes per command string entry */
+	dev->mtu = priv->chan->max_ptn_entries(priv->chan) * 2;
+	return 0;
+}
+
+static int snf_open(struct net_device *dev)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	ret = priv->chan->start(priv->chan);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+
+static int snf_stop(struct net_device *dev)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	ret = priv->chan->stop(priv->chan);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+
+static int snf_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	switch (cmd) {
+	case SIOCSHWTSTAMP:
+		return hw_timestamp_set(dev, ifr);
+
+	case SIOCGHWTSTAMP:
+		return hw_timestamp_get(dev, ifr);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int snf_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	struct snf_chan *sch = priv->chan;
+	unsigned long flags;
+	int ret;
+
+	/* When a packet is sent to the netdev it is assumed to
+	 * contain a new command string. So apply it.
+	 */
+	spin_lock_irqsave(&priv->lock, flags);
+	sch->stop(sch);
+	ret = sch->set_pattern(sch, skb->data, skb->len / 2);
+	sch->start(sch);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (ret < 0) {
+		dev->stats.tx_dropped++;
+	} else {
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += skb->len;
+	}
+
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops snf_netdev_ops = {
+	.ndo_init       = snf_init,
+	.ndo_open       = snf_open,
+	.ndo_stop       = snf_stop,
+	.ndo_start_xmit	= snf_start_xmit,
+	.ndo_do_ioctl   = snf_ioctl
+};
+
+static void snf_setup(struct net_device *dev)
+{
+	dev->netdev_ops   = &snf_netdev_ops;
+	dev->tx_queue_len = 1;
+	dev->flags        = IFF_NOARP;
+	dev->type         = ARPHRD_NONE;
+}
+
+/* Initialise netdev for a sniffer channel */
+int snf_channel_add(struct snf_chan *sch, const char *name)
+{
+	int ret;
+	struct net_device *ndev;
+	struct snf_ndev_state *priv;
+
+	ndev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN, snf_setup);
+	if (!ndev)
+		return -ENOMEM;
+
+	priv = netdev_priv(ndev);
+	priv->chan = sch;
+	priv->rx_tstamp_enabled = false;
+	spin_lock_init(&priv->lock);
+
+	ret = register_netdev(ndev);
+	if (ret < 0) {
+		free_netdev(ndev);
+		return ret;
+	}
+
+	sch->cstate = ndev;
+	return 0;
+}
+EXPORT_SYMBOL(snf_channel_add);
+
+/* Release netdev for a sniffer channel and free resources */
+int snf_channel_remove(struct snf_chan *sch)
+{
+	struct net_device *ndev = (struct net_device *)sch->cstate;
+
+	unregister_netdev(ndev);
+	free_netdev(ndev);
+	return 0;
+}
+EXPORT_SYMBOL(snf_channel_remove);
+
+/* Send a packet to user space for a sniffer match event */
+int snf_channel_notify_match(struct snf_chan *sch, struct snf_match_evt *mt)
+{
+	struct net_device *ndev = (struct net_device *)sch->cstate;
+	struct snf_ndev_state *priv = netdev_priv(ndev);
+	struct sk_buff *skb;
+	struct skb_shared_hwtstamps *skts;
+
+	skb = netdev_alloc_skb(ndev, mt->len);
+	if (!skb) {
+		ndev->stats.rx_dropped++;
+		return -ENOMEM;
+	}
+
+	skb_put(skb, mt->len);
+	skb_copy_to_linear_data(skb, mt->data, mt->len);
+	if (mt->ts_valid && priv->rx_tstamp_enabled) {
+		skts = skb_hwtstamps(skb);
+		skts->hwtstamp = ns_to_ktime(mt->ts);
+	}
+	ndev->stats.rx_packets++;
+	ndev->stats.rx_bytes += mt->len;
+	netif_rx(skb);
+	return 0;
+}
+EXPORT_SYMBOL(snf_channel_notify_match);
+
+/* Suspend the interface */
+int snf_channel_suspend(struct snf_chan *sch)
+{
+	struct net_device *ndev = (struct net_device *)sch->cstate;
+	struct snf_ndev_state *priv = netdev_priv(ndev);
+	unsigned long flags;
+	int ret;
+
+	if (!netif_running(ndev))
+		return 0;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	ret = sch->stop(sch);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	netif_device_detach(ndev);
+	return ret;
+}
+EXPORT_SYMBOL(snf_channel_suspend);
+
+/* Resume the interface */
+int snf_channel_resume(struct snf_chan *sch)
+{
+	struct net_device *ndev = (struct net_device *)sch->cstate;
+	struct snf_ndev_state *priv = netdev_priv(ndev);
+	unsigned long flags;
+	int ret;
+
+	if (!netif_running(ndev))
+		return 0;
+
+	netif_device_attach(ndev);
+	spin_lock_irqsave(&priv->lock, flags);
+	ret = sch->start(sch);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(snf_channel_resume);
+
+static int __init snf_core_init(void)
+{
+	return 0;
+}
+
+static void __exit snf_core_cleanup(void)
+{
+}
+
+module_init(snf_core_init);
+module_exit(snf_core_cleanup);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Core packet sniffer driver");
+MODULE_AUTHOR("Linn Products Ltd");
+
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h b/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h
new file mode 100644
index 0000000..73a30ff
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h
@@ -0,0 +1,60 @@
+/*
+ * Packet sniffer core driver
+ * - this header provides the interface to specific backend packet
+ *   sniffer implementations
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#ifndef __SNF_CORE_H
+#define __SNF_CORE_H
+
+#include <linux/types.h>
+
+/* This is a global maximum. Each backend will have its own limit */
+#define MAX_MATCH_BYTES 512
+
+/* Sniffer channel data structure */
+struct snf_chan {
+	int  (*start)(struct snf_chan *sch);
+	int  (*stop)(struct snf_chan *sch);
+	int  (*set_pattern)(struct snf_chan *sch, const u8 *pattern, int count);
+	int  (*max_ptn_entries)(struct snf_chan *sch);
+	int  (*ts_enabled)(struct snf_chan *sch);
+	void *cstate;
+};
+
+/* Data from a sniffer match event */
+struct snf_match_evt {
+	int ts_valid;     /* flag indicating if timestamp is present */
+	u64 ts;           /* timestamp value */
+	u8 data[MAX_MATCH_BYTES]; /* packet data bytes matched by sniffer */
+	int len;          /* number of valid bytes in the 'data' buffer */
+};
+
+/* Registers a sniffer channel */
+int snf_channel_add(struct snf_chan *sch, const char *name);
+
+/* Removes a sniffer channel */
+int snf_channel_remove(struct snf_chan *sch);
+
+/* Send a packet to user space for a sniffer match event */
+int snf_channel_notify_match(struct snf_chan *sch, struct snf_match_evt *mt);
+
+/* Suspend and resume operations */
+int snf_channel_suspend(struct snf_chan *sch);
+int snf_channel_resume(struct snf_chan *sch);
+
+#endif
+
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH net-next v4 2/3] Linn packet sniffer core framework
@ 2015-02-24 16:48   ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-24 16:48 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree; +Cc: Stathis Voukelatos

The framework registers each backend sniffer channel as a netdev,
which can be accessed from user space through a raw packet socket.
Packets received from user space are treated as a command string
configuration. Each match event from the backend driver will
generate a packet with the matching bytes plus an optional
timestamp, if configured by the command string.

Signed-off-by: Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
---
 MAINTAINERS                                        |   6 +
 drivers/net/ethernet/Kconfig                       |   1 +
 drivers/net/ethernet/Makefile                      |   1 +
 drivers/net/ethernet/linn/Kconfig                  |  25 ++
 drivers/net/ethernet/linn/Makefile                 |  19 ++
 .../net/ethernet/linn/pkt-sniffer/core/Makefile    |  19 ++
 .../net/ethernet/linn/pkt-sniffer/core/snf_core.c  | 344 +++++++++++++++++++++
 .../net/ethernet/linn/pkt-sniffer/core/snf_core.h  |  60 ++++
 8 files changed, 475 insertions(+)
 create mode 100644 drivers/net/ethernet/linn/Kconfig
 create mode 100644 drivers/net/ethernet/linn/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 0597c5b..6186c0c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5828,6 +5828,12 @@ M:	Sasha Levin <sasha.levin@oracle.com>
 S:	Maintained
 F:	tools/lib/lockdep/
 
+LINN PACKET SNIFFER DRIVER
+M: Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+S: Maintained
+F: drivers/net/ethernet/linn/
+F: Documentation/devicetree/bindings/net/linn-ether-packet-sniffer.txt
+
 LINUX FOR IBM pSERIES (RS/6000)
 M:	Paul Mackerras <paulus@au.ibm.com>
 W:	http://www.ibm.com/linux/ltc/projects/ppc
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index eadcb05..ee4b3ed 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -103,6 +103,7 @@ config LANTIQ_ETOP
 	---help---
 	  Support for the MII0 inside the Lantiq SoC
 
+source "drivers/net/ethernet/linn/Kconfig"
 source "drivers/net/ethernet/marvell/Kconfig"
 source "drivers/net/ethernet/mellanox/Kconfig"
 source "drivers/net/ethernet/micrel/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 1367afc..f8071d3 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_NET_VENDOR_HP) += hp/
 obj-$(CONFIG_NET_VENDOR_IBM) += ibm/
 obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
 obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
+obj-$(CONFIG_NET_VENDOR_LINN) += linn/
 obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/
 obj-$(CONFIG_IP1000) += icplus/
 obj-$(CONFIG_JME) += jme.o
diff --git a/drivers/net/ethernet/linn/Kconfig b/drivers/net/ethernet/linn/Kconfig
new file mode 100644
index 0000000..6654f4e
--- /dev/null
+++ b/drivers/net/ethernet/linn/Kconfig
@@ -0,0 +1,25 @@
+#
+# Linn device configuration
+#
+
+config NET_VENDOR_LINN
+	bool "Linn devices"
+	---help---
+	  Say Y to add support for Linn Products devices.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about Linn devices. If you say Y, you will be asked for
+	  your specific device in the following questions.
+
+if NET_VENDOR_LINN
+
+menuconfig PKT_SNIFFER
+    tristate "Packet sniffer support"
+    ---help---
+    Say Y to add support for the packet sniffer driver framework.
+
+    The core driver can also be built as a module. If so, the module
+    will be called snf_core.
+
+endif # NET_VENDOR_LINN
diff --git a/drivers/net/ethernet/linn/Makefile b/drivers/net/ethernet/linn/Makefile
new file mode 100644
index 0000000..f3338f3
--- /dev/null
+++ b/drivers/net/ethernet/linn/Makefile
@@ -0,0 +1,19 @@
+###############################################################################
+# Makefile for the Linn Products device drivers
+#
+# Copyright (C) 2015 Linn Products Ltd
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# Written by:
+# Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+###############################################################################
+
+obj-$(CONFIG_PKT_SNIFFER) += pkt-sniffer/core/
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/core/Makefile b/drivers/net/ethernet/linn/pkt-sniffer/core/Makefile
new file mode 100644
index 0000000..4dc8f11
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/core/Makefile
@@ -0,0 +1,19 @@
+###############################################################################
+# Makefile for the Linn packet sniffer framework driver
+#
+# Copyright (C) 2015 Linn Products Ltd
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# Written by:
+# Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+###############################################################################
+
+obj-$(CONFIG_PKT_SNIFFER) += snf_core.o
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c b/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c
new file mode 100644
index 0000000..9490943
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.c
@@ -0,0 +1,344 @@
+/*
+ * The Linn packet sniffer allows incoming or outgoing data packets
+ * to be parsed, matched against a user-defined data pattern and
+ * timestamped.
+ *
+ * Packet filtering is driven by a user-supplied command string
+ * which consists of a series of interleaved command and data bytes.
+ * ie. the command string has the following format:
+ *  --------------------------------
+ *  | CMD | DATA | CMD | DATA | ....
+ *  --------------------------------
+ * The supported commands and their function is documented in the
+ * corresponding backend driver.
+ * Data returned to the user for each matched packet include selected
+ * data bytes from the packet and optionally a timestamp.
+ *
+ * This module is the packet sniffer core driver that handles
+ * the interface between the H/W backend modules and user space:
+ *
+ * - Each backend sniffer channel is registered as a netdev, eg. Ethernet
+ *   TX and RX are two different channels.
+ *
+ * - Access from user space is through AF_PACKET sockets bound to
+ *   the netdev
+ *
+ * - User space supplies the command string by writing a packet to a socket.
+ *   The packet will contain interleaved commands and data values as
+ *   shown above.
+ *
+ * - Data from each packet match event are also returned through an AF_PACKET
+ *   socket. Timestamps use the existing kernel timestamping framework,
+ *   ie. they are returned to the user through a socket control message
+ *   (ancillary data).
+ *
+ * Example usage:
+ *    - Open a socket
+ *         fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ *    - Bind it to the netdev
+ *         strcpy(ifr.ifr_name, "snfethrx0");
+ *         ioctl(fd, SIOCGIFINDEX, &ifr);
+ *         ll.sll_family = AF_PACKET;
+ *         ll.sll_ifindex = ifr.ifr_ifindex;
+ *         bind(fd, (struct sockaddr *) &ll, sizeof(ll));
+ *    - Enable timestamping at the driver and socket level
+ *         ioctl(fd, SIOCSHWTSTAMP, &ifr);
+ *         opt = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE;
+ *         setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &opt, sizeof(opt));
+ *    - Configure a command string
+ *         char buf[4] = {0x03, 0xAB, 0x4, 0x00};
+ *         write(fd, buf, 4);
+ *    - Wait for a packet match
+ *         select(fd+1, &rfds, NULL, NULL, NULL);
+ *    - Read data
+ *         recvmsg(fd, &msg, 0);
+ *    - Timestamp will be available through a control message
+ *	   cmsg = CMSG_FIRSTHDR(&msg);
+ *         if (cmsg->cmsg_type == SO_TIMESTAMPING)
+ *		struct timespec *scmt = CMSG_DATA(cmsg);
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/net_tstamp.h>
+#include <linux/if_arp.h>
+#include <linux/spinlock.h>
+#include "snf_core.h"
+
+struct snf_ndev_state {
+	struct snf_chan *chan;
+	bool rx_tstamp_enabled;
+	spinlock_t lock;
+};
+
+static int hw_timestamp_set(struct net_device *dev, struct ifreq *ifr)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	struct hwtstamp_config tconf;
+
+	if (copy_from_user(&tconf, ifr->ifr_data, sizeof(tconf)))
+		return -EFAULT;
+
+	/* No TX timestamping supported.
+	 * This interface only receives packets from the sniffer backend
+	 */
+	if (tconf.tx_type != HWTSTAMP_TX_OFF)
+		return -ERANGE;
+
+	if (tconf.rx_filter != HWTSTAMP_FILTER_NONE) {
+		/* If timestamping is not enabled in the command string then
+		 * we cannot return any RX timestamps
+		 */
+		if (!priv->chan->ts_enabled(priv->chan))
+			return -ERANGE;
+		priv->rx_tstamp_enabled = true;
+		tconf.rx_filter = HWTSTAMP_FILTER_ALL;
+	} else {
+		priv->rx_tstamp_enabled = false;
+	}
+
+	return copy_to_user(ifr->ifr_data, &tconf, sizeof(tconf)) ? -EFAULT : 0;
+}
+
+static int hw_timestamp_get(struct net_device *dev, struct ifreq *ifr)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	struct hwtstamp_config tconf;
+
+	memset(&tconf, 0, sizeof(tconf));
+	tconf.tx_type = HWTSTAMP_TX_OFF;
+	/* We also need to check here that the current command string
+	 * will cause timestamps to be generated
+	 */
+	tconf.rx_filter = (priv->rx_tstamp_enabled &&
+			   priv->chan->ts_enabled(priv->chan)) ?
+			   HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
+
+	return copy_to_user(ifr->ifr_data, &tconf, sizeof(tconf)) ? -EFAULT : 0;
+}
+
+static int snf_init(struct net_device *dev)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+
+	/* Two bytes per command string entry */
+	dev->mtu = priv->chan->max_ptn_entries(priv->chan) * 2;
+	return 0;
+}
+
+static int snf_open(struct net_device *dev)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	ret = priv->chan->start(priv->chan);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+
+static int snf_stop(struct net_device *dev)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	ret = priv->chan->stop(priv->chan);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+
+static int snf_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	switch (cmd) {
+	case SIOCSHWTSTAMP:
+		return hw_timestamp_set(dev, ifr);
+
+	case SIOCGHWTSTAMP:
+		return hw_timestamp_get(dev, ifr);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int snf_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct snf_ndev_state *priv = netdev_priv(dev);
+	struct snf_chan *sch = priv->chan;
+	unsigned long flags;
+	int ret;
+
+	/* When a packet is sent to the netdev it is assumed to
+	 * contain a new command string. So apply it.
+	 */
+	spin_lock_irqsave(&priv->lock, flags);
+	sch->stop(sch);
+	ret = sch->set_pattern(sch, skb->data, skb->len / 2);
+	sch->start(sch);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (ret < 0) {
+		dev->stats.tx_dropped++;
+	} else {
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += skb->len;
+	}
+
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops snf_netdev_ops = {
+	.ndo_init       = snf_init,
+	.ndo_open       = snf_open,
+	.ndo_stop       = snf_stop,
+	.ndo_start_xmit	= snf_start_xmit,
+	.ndo_do_ioctl   = snf_ioctl
+};
+
+static void snf_setup(struct net_device *dev)
+{
+	dev->netdev_ops   = &snf_netdev_ops;
+	dev->tx_queue_len = 1;
+	dev->flags        = IFF_NOARP;
+	dev->type         = ARPHRD_NONE;
+}
+
+/* Initialise netdev for a sniffer channel */
+int snf_channel_add(struct snf_chan *sch, const char *name)
+{
+	int ret;
+	struct net_device *ndev;
+	struct snf_ndev_state *priv;
+
+	ndev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN, snf_setup);
+	if (!ndev)
+		return -ENOMEM;
+
+	priv = netdev_priv(ndev);
+	priv->chan = sch;
+	priv->rx_tstamp_enabled = false;
+	spin_lock_init(&priv->lock);
+
+	ret = register_netdev(ndev);
+	if (ret < 0) {
+		free_netdev(ndev);
+		return ret;
+	}
+
+	sch->cstate = ndev;
+	return 0;
+}
+EXPORT_SYMBOL(snf_channel_add);
+
+/* Release netdev for a sniffer channel and free resources */
+int snf_channel_remove(struct snf_chan *sch)
+{
+	struct net_device *ndev = (struct net_device *)sch->cstate;
+
+	unregister_netdev(ndev);
+	free_netdev(ndev);
+	return 0;
+}
+EXPORT_SYMBOL(snf_channel_remove);
+
+/* Send a packet to user space for a sniffer match event */
+int snf_channel_notify_match(struct snf_chan *sch, struct snf_match_evt *mt)
+{
+	struct net_device *ndev = (struct net_device *)sch->cstate;
+	struct snf_ndev_state *priv = netdev_priv(ndev);
+	struct sk_buff *skb;
+	struct skb_shared_hwtstamps *skts;
+
+	skb = netdev_alloc_skb(ndev, mt->len);
+	if (!skb) {
+		ndev->stats.rx_dropped++;
+		return -ENOMEM;
+	}
+
+	skb_put(skb, mt->len);
+	skb_copy_to_linear_data(skb, mt->data, mt->len);
+	if (mt->ts_valid && priv->rx_tstamp_enabled) {
+		skts = skb_hwtstamps(skb);
+		skts->hwtstamp = ns_to_ktime(mt->ts);
+	}
+	ndev->stats.rx_packets++;
+	ndev->stats.rx_bytes += mt->len;
+	netif_rx(skb);
+	return 0;
+}
+EXPORT_SYMBOL(snf_channel_notify_match);
+
+/* Suspend the interface */
+int snf_channel_suspend(struct snf_chan *sch)
+{
+	struct net_device *ndev = (struct net_device *)sch->cstate;
+	struct snf_ndev_state *priv = netdev_priv(ndev);
+	unsigned long flags;
+	int ret;
+
+	if (!netif_running(ndev))
+		return 0;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	ret = sch->stop(sch);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	netif_device_detach(ndev);
+	return ret;
+}
+EXPORT_SYMBOL(snf_channel_suspend);
+
+/* Resume the interface */
+int snf_channel_resume(struct snf_chan *sch)
+{
+	struct net_device *ndev = (struct net_device *)sch->cstate;
+	struct snf_ndev_state *priv = netdev_priv(ndev);
+	unsigned long flags;
+	int ret;
+
+	if (!netif_running(ndev))
+		return 0;
+
+	netif_device_attach(ndev);
+	spin_lock_irqsave(&priv->lock, flags);
+	ret = sch->start(sch);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(snf_channel_resume);
+
+static int __init snf_core_init(void)
+{
+	return 0;
+}
+
+static void __exit snf_core_cleanup(void)
+{
+}
+
+module_init(snf_core_init);
+module_exit(snf_core_cleanup);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Core packet sniffer driver");
+MODULE_AUTHOR("Linn Products Ltd");
+
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h b/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h
new file mode 100644
index 0000000..73a30ff
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/core/snf_core.h
@@ -0,0 +1,60 @@
+/*
+ * Packet sniffer core driver
+ * - this header provides the interface to specific backend packet
+ *   sniffer implementations
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#ifndef __SNF_CORE_H
+#define __SNF_CORE_H
+
+#include <linux/types.h>
+
+/* This is a global maximum. Each backend will have its own limit */
+#define MAX_MATCH_BYTES 512
+
+/* Sniffer channel data structure */
+struct snf_chan {
+	int  (*start)(struct snf_chan *sch);
+	int  (*stop)(struct snf_chan *sch);
+	int  (*set_pattern)(struct snf_chan *sch, const u8 *pattern, int count);
+	int  (*max_ptn_entries)(struct snf_chan *sch);
+	int  (*ts_enabled)(struct snf_chan *sch);
+	void *cstate;
+};
+
+/* Data from a sniffer match event */
+struct snf_match_evt {
+	int ts_valid;     /* flag indicating if timestamp is present */
+	u64 ts;           /* timestamp value */
+	u8 data[MAX_MATCH_BYTES]; /* packet data bytes matched by sniffer */
+	int len;          /* number of valid bytes in the 'data' buffer */
+};
+
+/* Registers a sniffer channel */
+int snf_channel_add(struct snf_chan *sch, const char *name);
+
+/* Removes a sniffer channel */
+int snf_channel_remove(struct snf_chan *sch);
+
+/* Send a packet to user space for a sniffer match event */
+int snf_channel_notify_match(struct snf_chan *sch, struct snf_match_evt *mt);
+
+/* Suspend and resume operations */
+int snf_channel_suspend(struct snf_chan *sch);
+int snf_channel_resume(struct snf_chan *sch);
+
+#endif
+
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH net-next v4 3/3] Linn Ethernet packet sniffer driver
  2015-02-24 16:48 ` Stathis Voukelatos
@ 2015-02-24 16:48   ` Stathis Voukelatos
  -1 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-24 16:48 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree; +Cc: Stathis Voukelatos

Driver for the Ethernet Mii packet sniffer H/W module found in
the IMG Pistachio SoC.

Signed-off-by: Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
---
 drivers/net/ethernet/linn/Kconfig                  |  11 +
 drivers/net/ethernet/linn/Makefile                 |   1 +
 .../linn/pkt-sniffer/backends/ether/Makefile       |  20 +
 .../linn/pkt-sniffer/backends/ether/channel.c      | 444 +++++++++++++++++++++
 .../linn/pkt-sniffer/backends/ether/channel.h      |  80 ++++
 .../ethernet/linn/pkt-sniffer/backends/ether/hw.h  |  46 +++
 .../linn/pkt-sniffer/backends/ether/platform.c     | 318 +++++++++++++++
 7 files changed, 920 insertions(+)
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c

diff --git a/drivers/net/ethernet/linn/Kconfig b/drivers/net/ethernet/linn/Kconfig
index 6654f4e..bbfd6a4 100644
--- a/drivers/net/ethernet/linn/Kconfig
+++ b/drivers/net/ethernet/linn/Kconfig
@@ -22,4 +22,15 @@ menuconfig PKT_SNIFFER
     The core driver can also be built as a module. If so, the module
     will be called snf_core.
 
+config PKT_SNIFFER_ETHER
+    tristate "Ethernet packet sniffer"
+    depends on PKT_SNIFFER
+    help
+        Say Y here if you want to use the Ethernet packet sniffer
+        module by Linn Products Ltd. It can be found in the upcoming
+        Pistachio SoC by Imagination Technologies.
+
+        The driver can also be built as a module. If so, the module
+        will be called snf_ether.
+
 endif # NET_VENDOR_LINN
diff --git a/drivers/net/ethernet/linn/Makefile b/drivers/net/ethernet/linn/Makefile
index f3338f3..f51eb66 100644
--- a/drivers/net/ethernet/linn/Makefile
+++ b/drivers/net/ethernet/linn/Makefile
@@ -17,3 +17,4 @@
 ###############################################################################
 
 obj-$(CONFIG_PKT_SNIFFER) += pkt-sniffer/core/
+obj-$(CONFIG_PKT_SNIFFER_ETHER) += pkt-sniffer/backends/ether/
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile
new file mode 100644
index 0000000..1f97e51
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile
@@ -0,0 +1,20 @@
+###############################################################################
+# Makefile for the Linn ethernet packet sniffer driver
+#
+# Copyright (C) 2015 Linn Products Ltd
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# Written by:
+# Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+###############################################################################
+
+obj-$(CONFIG_PKT_SNIFFER_ETHER) += snf_ether.o
+snf_ether-objs := platform.o channel.o
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c
new file mode 100644
index 0000000..87ec790
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c
@@ -0,0 +1,444 @@
+/*
+ * Ethernet Mii packet sniffer driver
+ *  - channel functions
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#include <linux/io.h>
+#include <linux/hrtimer.h>
+#include <linux/clocksource.h>
+#include "../../core/snf_core.h"
+#include "hw.h"
+#include "channel.h"
+
+#define to_ether_snf_chan(dev) container_of(dev, struct ether_snf_chan, chan)
+
+#define CMD_DONTCARE	0
+#define CMD_MATCH	1
+#define CMD_COPY	2
+#define CMD_MATCHSTAMP	3
+#define CMD_COPYDONE	4
+
+/* Checks if the supplied command string is compatible with the
+ * capabilities of the H/W.
+ */
+static bool validate_pattern(
+			struct ether_snf_chan *ch,
+			const u8 *buf,
+			int count)
+{
+	int i, complete, max_copy_bytes;
+	int ts = 0;
+	int copy_before = 0;
+	int copy_after = 0;
+
+	if (count > ch->max_cmds)
+		return false;
+
+	/* Iterate through the commands in the string */
+	for (i = 0, complete = 0; (i < count) && !complete; i++) {
+		u8 cmd = buf[2 * i];
+
+		switch (cmd) {
+		case CMD_DONTCARE:
+		case CMD_MATCH:
+			break;
+
+		case CMD_MATCHSTAMP:
+			/* The timestamp needs to be word-aligned in the FIFO
+			 * therefore, the number of 'copy' commands before it
+			 * needs to be a multiple of 4
+			 */
+			if (copy_before & 3)
+				return false;
+			/* Signal that a timestamp will be present */
+			ts = 1;
+			break;
+
+		case CMD_COPY:
+			/* Increment count of bytes that will be returned */
+			if (ts)
+				copy_after++;
+			else
+				copy_before++;
+			break;
+
+		case CMD_COPYDONE:
+			/* Increment count of bytes that will be returned
+			 * This command terminates the string
+			 */
+			if (ts)
+				copy_after++;
+			else
+				copy_before++;
+			/* This command completes the command string */
+			complete = 1;
+			break;
+
+		default:
+			/* Invalid command id */
+			return false;
+		}
+	}
+
+	/* Check if the string was properly terminated
+	 * and contained valid number of commands
+	 */
+	if (complete) {
+		max_copy_bytes = ch->fifo_blk_words * 4;
+		if (ts)
+			max_copy_bytes -= 4;
+		/* Too many copy commands will case the FIFO
+		 * to wrap around
+		 */
+		if ((copy_before + copy_after) > max_copy_bytes)
+			return false;
+		ch->nfb_before = copy_before;
+		ch->nfb_after = copy_after;
+		ch->evt.ts_valid = ts;
+		ch->evt.len = ch->nfb_before + ch->nfb_after;
+		return true;
+	}
+
+	/* Command string not terminated */
+	return false;
+}
+
+/* Channel methods */
+
+/* Enables the channel */
+static int esnf_start(struct snf_chan *dev)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+
+	if (!ch->started) {
+		ch->evt.ts = 0;
+		/* Enable interrupts */
+		iowrite32(ch->data_irq_bit | ch->full_irq_bit,
+			  ch->regs + SET_INTERRUPT_ENABLE);
+		/* Enable the packet matching logic */
+		iowrite32(ENABLE_BIT, ch->reg_enable);
+
+		ch->started = 1;
+		dev_info(ch->dev, "%s: started\n", ch->name);
+	} else {
+		dev_dbg(ch->dev, "%s: already running\n", ch->name);
+	}
+
+	return 0;
+}
+
+/* Disables the channel */
+static int esnf_stop(struct snf_chan *dev)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+
+	if (ch->started) {
+		/* Disable interrupts */
+		iowrite32(ch->data_irq_bit | ch->full_irq_bit,
+			  ch->regs + CLEAR_INTERRUPT_ENABLE);
+		/* Stop the sniffer channel */
+		iowrite32(0, ch->reg_enable);
+		/* Clear any pending interrupts */
+		iowrite32(ch->data_irq_bit | ch->full_irq_bit,
+			  ch->regs + INTERRUPT_STATUS);
+
+		ch->started = 0;
+		dev_info(ch->dev, "%s: stopped\n", ch->name);
+	} else {
+		dev_dbg(ch->dev, "%s: already stopped\n", ch->name);
+	}
+
+	return 0;
+}
+
+/* Sets the command string (pattern) for the channel
+ * The bytes in the pattern buffer are in the following order:
+ */
+static int esnf_set_pattern(struct snf_chan *dev, const u8 *pattern, int count)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+	int i, shift = 0;
+	u32  val = 0, *ptr;
+
+	dev_info(ch->dev, "%s: set cmd pattern with %d entries\n",
+		 ch->name, count);
+
+	if (ch->started) {
+		dev_err(ch->dev,
+			"%s: cannot apply cmd pattern. Channel is active\n",
+			ch->name);
+		return -EBUSY;
+	}
+
+	if (!validate_pattern(ch, pattern, count)) {
+		dev_err(ch->dev,
+			"%s: invalid cmd pattern\n",
+			ch->name);
+		return -EINVAL;
+	}
+
+	for (ptr = ch->cmd_ram, i = 0, shift = 24; i < (2 * count); i++) {
+		val |= ((u32)pattern[i]) << shift;
+		if (!shift) {
+			iowrite32(val, ptr++);
+			val = 0;
+			shift = 24;
+		} else {
+			shift -= 8;
+		}
+	}
+	if (shift)
+		iowrite32(val, ptr);
+
+	return 0;
+}
+
+/* Returns max number of commands supported by the channel */
+static int esnf_max_ptn_entries(struct snf_chan *dev)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+
+	return ch->max_cmds;
+}
+
+static int esnf_ts_enabled(struct snf_chan *dev)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+
+	return ch->evt.ts_valid;
+}
+
+/* Gray decoder */
+static u32 gray_decode(u32 gray)
+{
+	gray ^= (gray >> 16);
+	gray ^= (gray >> 8);
+	gray ^= (gray >> 4);
+	gray ^= (gray >> 2);
+	gray ^= (gray >> 1);
+	return gray;
+}
+
+/* Read a block from the data FIFO */
+static void read_fifo_data(struct ether_snf_chan *ch)
+{
+	int i;
+	u32 val, *ptr;
+	int ts = ch->evt.ts_valid;
+	int dw = ch->fifo_blk_words;
+	int bytes_before = ch->nfb_before;
+	int bytes_after = ch->nfb_after;
+
+	ptr = (u32 *)ch->evt.data;
+	for (i = 0; i < dw; i++) {
+		val = ioread32(ch->reg_fifo);
+		if (bytes_before > 0) {
+			/* Bytes before the timestamp */
+			*ptr++ = cpu_to_be32(val);
+			bytes_before -= 4;
+		} else if (ts) {
+			ch->raw_tstamp = gray_decode(val);
+			/* First timestamp since the channel was started.
+			 * Initialise the timecounter
+			 */
+			if (!ch->evt.ts)
+				timecounter_init(
+					&ch->tc,
+					&ch->cc,
+					ktime_to_ns(ktime_get_real()));
+			ch->evt.ts = timecounter_read(&ch->tc);
+			ts = 0;
+		} else if (bytes_after > 0) {
+			/* Bytes after the timestamp */
+			*ptr++ = cpu_to_be32(val);
+			bytes_after -= 4;
+		}
+	}
+}
+
+/* Read method for the timestamp cycle counter
+ * Returns the last received timestamp value
+ */
+static cycle_t esnf_cyclecounter_read(const struct cyclecounter *cc)
+{
+	struct ether_snf_chan *ch = container_of(cc, struct ether_snf_chan, cc);
+
+	return ch->raw_tstamp;
+}
+
+/* Taken from clocks_calc_mult_shift() in kernel/time/clocksource.c
+ * Unfortunately that function is not exported by the kernel
+ */
+static void esnf_clocks_calc_mult_shift(
+				u32 *mult,
+				u32 *shift,
+				u32 from,
+				u32 to,
+				u32 maxsec)
+{
+	u64 tmp;
+	u32 sft, sftacc = 32;
+
+	/* Calculate the shift factor which is limiting the conversion
+	 * range:
+	 */
+	tmp = ((u64)maxsec * from) >> 32;
+	while (tmp) {
+		tmp >>= 1;
+		sftacc--;
+	}
+
+	/* Find the conversion shift/mult pair which has the best
+	 * accuracy and fits the maxsec conversion range:
+	 */
+	for (sft = 32; sft > 0; sft--) {
+		tmp = (u64)to << sft;
+		tmp += from / 2;
+		do_div(tmp, from);
+		if ((tmp >> sftacc) == 0)
+			break;
+	}
+	*mult = tmp;
+	*shift = sft;
+}
+
+/* Follows the logic of __clocksource_updatefreq_scale() in
+ * in kernel/time/clocksource.c
+ */
+static void calc_mult_shift(u32 *mult, u32 *shift, cycle_t mask, u32 freq)
+{
+	u64 sec;
+
+	sec = mask - (mask >> 3);
+	do_div(sec, freq);
+	if (!sec)
+		sec = 1;
+	else if (sec > 600 && mask > UINT_MAX)
+		sec = 600;
+	esnf_clocks_calc_mult_shift(mult, shift, freq, NSEC_PER_SEC, sec);
+}
+
+/* Initialises a sniffer channel */
+int channel_init(
+	struct ether_snf_chan *ch,
+	struct platform_device *pdev,
+	void *regs,
+	int fifo_blk_words,
+	u32 tstamp_hz,
+	u32 tstamp_bits,
+	int tx)
+{
+	struct resource *res;
+	u32 *ptr;
+	int i;
+
+	ch->regs = regs;
+	ch->dev = &pdev->dev;
+	ch->data_irq_bit = tx ? TX_DATA_IRQ_BIT : RX_DATA_IRQ_BIT;
+	ch->full_irq_bit = tx ? TX_FULL_IRQ_BIT : RX_FULL_IRQ_BIT;
+	ch->reg_enable = ch->regs +
+			 (tx ? TX_SNIFFER_ENABLE : RX_SNIFFER_ENABLE);
+	ch->reg_fifo = ch->regs + (tx ? TX_FIFO_DAT : RX_FIFO_DAT);
+
+	/* Retrieve and remap the address space for the command memory */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   tx ? "tx-ram" : "rx-ram");
+	if (!res)
+		return -ENOSYS;
+	ch->cmd_ram = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ch->cmd_ram))
+		return PTR_ERR(ch->cmd_ram);
+
+	/* It is 2 bytes/command, hence divide by 2 */
+	ch->max_cmds = resource_size(res) / 2;
+
+	/* Initialise the command string RAM */
+	for (i = 0, ptr = ch->cmd_ram; i < resource_size(res); i += 4)
+		iowrite32((CMD_DONTCARE << 24) | (CMD_DONTCARE << 8),
+			  ptr++);
+
+	ch->fifo_blk_words = fifo_blk_words;
+	ch->started = 0;
+
+	/* Initialise the timestamp cycle counter */
+	ch->cc.read = esnf_cyclecounter_read;
+	ch->cc.mask = CLOCKSOURCE_MASK(tstamp_bits);
+	calc_mult_shift(&ch->cc.mult, &ch->cc.shift, ch->cc.mask, tstamp_hz);
+
+	/* Register the channel methods */
+	ch->chan.start = esnf_start;
+	ch->chan.stop = esnf_stop;
+	ch->chan.set_pattern = esnf_set_pattern;
+	ch->chan.max_ptn_entries = esnf_max_ptn_entries;
+	ch->chan.ts_enabled = esnf_ts_enabled;
+
+	strncpy(ch->name, tx ? "TX" : "RX", MAX_CHAN_NAME_SIZE - 1);
+
+	dev_dbg(ch->dev, "%s: channel initialized\n", ch->name);
+
+	return 0;
+}
+
+/* Registers the channel with the sniffer core module */
+int channel_register(struct ether_snf_chan *ch, const char *name)
+{
+	int ret;
+
+	ret = snf_channel_add(&ch->chan, name);
+	if (ret < 0)
+		return ret;
+
+	dev_info(ch->dev, "%s channel added\n", ch->name);
+	return 0;
+}
+
+/* Unregisters the channel */
+int channel_unregister(struct ether_snf_chan *ch)
+{
+	int ret;
+
+	ch->chan.stop(&ch->chan);
+	ret = snf_channel_remove(&ch->chan);
+	if (!ret)
+		dev_info(ch->dev, "%s channel removed\n", ch->name);
+	return ret;
+}
+
+/* Process match event data */
+void channel_data_available(struct ether_snf_chan *ch)
+{
+	int ret;
+
+	dev_dbg(ch->dev, "%s match event\n", ch->name);
+
+	read_fifo_data(ch);
+	ret = snf_channel_notify_match(&ch->chan, &ch->evt);
+	if (ret < 0)
+		dev_err(ch->dev, "%s: event notification failed\n", ch->name);
+}
+
+/* Suspend opertion */
+int channel_suspend(struct ether_snf_chan *ch)
+{
+	return snf_channel_suspend(&ch->chan);
+}
+
+/* Resume operation */
+int channel_resume(struct ether_snf_chan *ch)
+{
+	return snf_channel_resume(&ch->chan);
+}
+
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h
new file mode 100644
index 0000000..75b942e
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h
@@ -0,0 +1,80 @@
+/*
+ * Ethernet Mii packet sniffer driver
+ *  - channel interface
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#ifndef _ETHER_SNIFFER_CHANNEL_H_
+#define _ETHER_SNIFFER_CHANNEL_H_
+
+#include <linux/platform_device.h>
+#include <linux/timecounter.h>
+#include "../../core/snf_core.h"
+
+#define MAX_CHAN_NAME_SIZE 5
+
+struct ether_snf_chan {
+	/* Sniffer core structure */
+	struct snf_chan chan;
+	/* Pointer to device struct */
+	struct device *dev;
+	/* Registers */
+	u8 __iomem *regs;
+	/* Command string memory */
+	u32 __iomem *cmd_ram;
+	/* Bit number for the data IRQ */
+	int data_irq_bit;
+	/* Bit number for the FIFO full IRQ */
+	int full_irq_bit;
+	/* Channel enable register */
+	u8 __iomem *reg_enable;
+	/* Data FIFO register */
+	u8 __iomem *reg_fifo;
+	/* Max number of commands in the string */
+	int max_cmds;
+	/* Max matching bytes that can fit in a FIFO block */
+	int fifo_blk_words;
+	/* Number of bytes in the FIFO before the timestamp */
+	int nfb_before;
+	/* Number of bytes in the FIFO after the timestamp */
+	int nfb_after;
+	/* Channel active flag */
+	int started;
+	/* Last raw timestamp from the FIFO */
+	u32 raw_tstamp;
+	/* Channel name (only used by debug messages) */
+	char name[MAX_CHAN_NAME_SIZE];
+	/* Struct to hold data from a packet match */
+	struct snf_match_evt evt;
+	/* Cycle and time counters for tstamp handling */
+	struct cyclecounter cc;
+	struct timecounter tc;
+};
+
+int channel_init(
+		struct ether_snf_chan *ch,
+		struct platform_device *pdev,
+		void *regs,
+		int fifo_blk_words,
+		u32 tstamp_hz,
+		u32 tstamp_bits,
+		int tx);
+int channel_register(struct ether_snf_chan *ch, const char *name);
+int channel_unregister(struct ether_snf_chan *ch);
+void channel_data_available(struct ether_snf_chan *ch);
+int channel_suspend(struct ether_snf_chan *ch);
+int channel_resume(struct ether_snf_chan *ch);
+
+#endif
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h
new file mode 100644
index 0000000..edb1093
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h
@@ -0,0 +1,46 @@
+/*
+ * Ethernet Mii packet sniffer driver
+ *  - register map
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#ifndef _ETHER_SNIFFER_HW_H_
+#define _ETHER_SNIFFER_HW_H_
+
+#include <linux/bitops.h>
+
+/* Registers */
+#define INTERRUPT_ENABLE        0x00
+#define SET_INTERRUPT_ENABLE    0x04
+#define CLEAR_INTERRUPT_ENABLE  0x08
+#define INTERRUPT_STATUS        0x0c
+#define TX_FIFO_DAT             0x10
+#define RX_FIFO_DAT             0x14
+#define TX_FIFO_OCC             0x18
+#define RX_FIFO_OCC             0x1c
+#define TX_SNIFFER_ENABLE       0x20
+#define RX_SNIFFER_ENABLE       0x24
+
+/* IRQ register bits */
+#define TX_DATA_IRQ_BIT         BIT(0)
+#define RX_DATA_IRQ_BIT         BIT(1)
+#define TX_FULL_IRQ_BIT         BIT(2)
+#define RX_FULL_IRQ_BIT         BIT(3)
+
+/* Enable register bits */
+#define ENABLE_BIT              BIT(0)
+
+#endif
+
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c
new file mode 100644
index 0000000..4da039a
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c
@@ -0,0 +1,318 @@
+/*
+ * This module is the driver for the Linn Ethernet Mii packet sniffer
+ * H/W module. It allows incoming and outoing Ethernet packets to be
+ * parsed, matched against a user-defined pattern and timestamped.
+ * It sits between an Ethernet MAC and PHY and is completely passive
+ * with respect to Ethernet frames.
+ *
+ * Packet filtering is driven by a user-supplied command string
+ * which consists of a series of interleaved command and data bytes.
+ * ie. the command string has the following format:
+ *  --------------------------------
+ *  | CMD | DATA | CMD | DATA | ....
+ *  --------------------------------
+ * The following commands are supported:
+ * 0 - Don't care
+ * 1 - Match: packet data must match command string byte
+ * 2 - Copy: packet data will be copied to FIFO
+ * 3 - Match/Stamp: if packet data matches string byte, a timestamp
+ *                  is copied into the FIFO
+ * 4 - Copy/Done: packet data will be copied into the FIFO.
+ *                This command terminates the command string.
+ * Example:
+ *   0x00, 0x00, 0x01, 0xDE, 0x03, 0x20, 0x04, 0x00
+ *   The above string will match Ethernet packets where the 2nd and 3rd
+ *   bytes of the destination MAC address are 0xDE and 0x22.
+ *   For each matched packet a timestamp and the 4th byte of the destination
+ *   MAC will be copied to the FIFO
+ *
+ * - An IRQ is triggered for every packet match event
+ * - The modules includes a H/W block based FIFO where matched packet data
+ *   and timestamp values are placed
+ * - The FIFO is accessed through a single register
+ * - An IRQ is also generated if all FIFO blocks are filled.
+ * - Timestamps are Gray encoded
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include "../../core/snf_core.h"
+#include "hw.h"
+#include "channel.h"
+
+/* Names for the TX and RX channel net interfaces */
+static const char tx_channel_name[] = "snfethtx%d";
+static const char rx_channel_name[] = "snfethrx%d";
+
+struct ether_snf {
+	u8 __iomem *regs;
+	int irq;
+	struct clk *sys_clk;
+	struct clk *ts_clk;
+	struct ether_snf_chan txc;
+	struct ether_snf_chan rxc;
+};
+
+/* Interrupt handler */
+static irqreturn_t esnf_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = (struct platform_device *)dev_id;
+	struct ether_snf *esnf = (struct ether_snf *)platform_get_drvdata(pdev);
+	u32 irq_status;
+
+	if (unlikely(esnf->irq != irq))
+		return IRQ_NONE;
+
+	irq_status = ioread32(esnf->regs + INTERRUPT_STATUS) &
+				 ioread32(esnf->regs + INTERRUPT_ENABLE);
+
+	dev_dbg(&pdev->dev, "irq: 0x%08x\n", irq_status);
+
+	/* TX FIFO full */
+	if (unlikely(irq_status & TX_FULL_IRQ_BIT))
+		dev_notice(&pdev->dev, "TX FIFO full\n");
+
+	/* RX FIFO full */
+	if (unlikely(irq_status & RX_FULL_IRQ_BIT))
+		dev_notice(&pdev->dev, "RX FIFO full\n");
+
+	/* TX match data available */
+	if (irq_status & TX_DATA_IRQ_BIT) {
+		dev_dbg(&pdev->dev, "TX data\n");
+		channel_data_available(&esnf->txc);
+	}
+
+	/* RX match data available */
+	if (irq_status & RX_DATA_IRQ_BIT) {
+		dev_dbg(&pdev->dev, "RX data\n");
+		channel_data_available(&esnf->rxc);
+	}
+
+	/* Clear interrupts */
+	iowrite32(irq_status, esnf->regs + INTERRUPT_STATUS);
+
+	return IRQ_HANDLED;
+}
+
+/* Called when the packet sniffer device is bound with the driver */
+static int esnf_driver_probe(struct platform_device *pdev)
+{
+	struct ether_snf *esnf;
+	struct resource *res;
+	int ret, irq;
+	u32 fifo_blk_words, ts_hz, ts_bits;
+	void __iomem *regs;
+	struct device_node *ofn = pdev->dev.of_node;
+
+	/* Allocate the device data structure */
+	esnf = devm_kzalloc(&pdev->dev, sizeof(*esnf), GFP_KERNEL);
+	if (!esnf)
+		return -ENOMEM;
+
+	/* Retrieve and remap register memory space */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+	esnf->regs = regs;
+
+	if (!ofn)
+		return -ENODEV;
+
+	/* Read requirede properties from the device tree node */
+	ret = of_property_read_u32(
+				ofn,
+				"fifo-block-words",
+				&fifo_blk_words);
+	if (ret < 0)
+		return ret;
+
+	if (((fifo_blk_words - 1) * 4) > MAX_MATCH_BYTES) {
+		dev_err(&pdev->dev,
+			"Invalid FIFO block size entry in device tree\n");
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32(
+				ofn,
+				"tstamp-bits",
+				&ts_bits);
+	if (ret < 0)
+		return ret;
+
+	/* Enable peripheral bus and timstamp clocks */
+	esnf->sys_clk = devm_clk_get(&pdev->dev, "sys");
+	if (IS_ERR(esnf->sys_clk)) {
+		ret = PTR_ERR(esnf->sys_clk);
+		return ret;
+	}
+	ret = clk_prepare_enable(esnf->sys_clk);
+	if (ret < 0)
+		return ret;
+
+	esnf->ts_clk = devm_clk_get(&pdev->dev, "tstamp");
+	if (IS_ERR(esnf->ts_clk)) {
+		ret = PTR_ERR(esnf->ts_clk);
+		goto fail1;
+	}
+	ret = clk_prepare_enable(esnf->ts_clk);
+	if (ret < 0)
+		goto fail1;
+
+	/* Initialise the TX and RX channels */
+	ts_hz = clk_get_rate(esnf->ts_clk);
+	ret = channel_init(
+			&esnf->txc,
+			pdev,
+			regs,
+			fifo_blk_words,
+			ts_hz,
+			ts_bits,
+			1);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to init TX channel (%d)\n", ret);
+		goto fail2;
+	}
+	ret = channel_init(
+			&esnf->rxc,
+			pdev,
+			regs,
+			fifo_blk_words,
+			ts_hz,
+			ts_bits,
+			0);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to init RX channel (%d)\n", ret);
+		goto fail2;
+	}
+
+	/* Register the channels with the sniffer core module */
+	ret = channel_register(&esnf->txc, tx_channel_name);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register TX chan (%d)\n", ret);
+		goto fail2;
+	}
+	ret = channel_register(&esnf->rxc, rx_channel_name);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register RX chan (%d)\n", ret);
+		goto fail3;
+	}
+
+	platform_set_drvdata(pdev, esnf);
+
+	/* Register the interrupt handler */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		goto fail4;
+	esnf->irq = irq;
+	ret = devm_request_irq(
+			&pdev->dev,
+			irq,
+			esnf_interrupt,
+			0,
+			KBUILD_MODNAME,
+			pdev);
+	if (ret < 0)
+		goto fail4;
+
+	return 0;
+
+fail4:
+	channel_unregister(&esnf->rxc);
+fail3:
+	channel_unregister(&esnf->txc);
+fail2:
+	clk_disable_unprepare(esnf->ts_clk);
+fail1:
+	clk_disable_unprepare(esnf->sys_clk);
+	return ret;
+}
+
+/* Called when the packet sniffer device unregisters with the driver */
+static int esnf_driver_remove(struct platform_device *pdev)
+{
+	struct ether_snf *esnf = (struct ether_snf *)platform_get_drvdata(pdev);
+	int ret;
+
+	ret = channel_unregister(&esnf->txc);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to unregister TX chan (%d)\n", ret);
+		return ret;
+	}
+	ret = channel_unregister(&esnf->rxc);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to unregister RX chan (%d)\n", ret);
+		return ret;
+	}
+	clk_disable_unprepare(esnf->ts_clk);
+	clk_disable_unprepare(esnf->sys_clk);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/* Driver suspend method */
+static int esnf_driver_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ether_snf *esnf = (struct ether_snf *)platform_get_drvdata(pdev);
+
+	channel_suspend(&esnf->txc);
+	channel_suspend(&esnf->rxc);
+	return 0;
+}
+
+/* Driver resume method */
+static int esnf_driver_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ether_snf *esnf = (struct ether_snf *)platform_get_drvdata(pdev);
+
+	channel_resume(&esnf->txc);
+	channel_resume(&esnf->rxc);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(esnf_pm_ops, esnf_driver_suspend, esnf_driver_resume);
+#endif
+
+static const struct of_device_id esnf_of_match_table[] = {
+	{ .compatible = "linn,eth-packet-sniffer" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, esnf_of_match_table);
+
+static struct platform_driver esnf_platform_driver = {
+	.driver = {
+		.name           = KBUILD_MODNAME,
+#ifdef CONFIG_PM
+		.pm	        = &esnf_pm_ops,
+#endif
+		.of_match_table = esnf_of_match_table,
+	},
+	.probe = esnf_driver_probe,
+	.remove = esnf_driver_remove,
+};
+
+module_platform_driver(esnf_platform_driver);
+
+MODULE_DESCRIPTION("Linn Ethernet Packet Sniffer");
+MODULE_AUTHOR("Linn Products Ltd");
+MODULE_LICENSE("GPL v2");
+
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH net-next v4 3/3] Linn Ethernet packet sniffer driver
@ 2015-02-24 16:48   ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-24 16:48 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree; +Cc: Stathis Voukelatos

Driver for the Ethernet Mii packet sniffer H/W module found in
the IMG Pistachio SoC.

Signed-off-by: Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
---
 drivers/net/ethernet/linn/Kconfig                  |  11 +
 drivers/net/ethernet/linn/Makefile                 |   1 +
 .../linn/pkt-sniffer/backends/ether/Makefile       |  20 +
 .../linn/pkt-sniffer/backends/ether/channel.c      | 444 +++++++++++++++++++++
 .../linn/pkt-sniffer/backends/ether/channel.h      |  80 ++++
 .../ethernet/linn/pkt-sniffer/backends/ether/hw.h  |  46 +++
 .../linn/pkt-sniffer/backends/ether/platform.c     | 318 +++++++++++++++
 7 files changed, 920 insertions(+)
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h
 create mode 100644 drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c

diff --git a/drivers/net/ethernet/linn/Kconfig b/drivers/net/ethernet/linn/Kconfig
index 6654f4e..bbfd6a4 100644
--- a/drivers/net/ethernet/linn/Kconfig
+++ b/drivers/net/ethernet/linn/Kconfig
@@ -22,4 +22,15 @@ menuconfig PKT_SNIFFER
     The core driver can also be built as a module. If so, the module
     will be called snf_core.
 
+config PKT_SNIFFER_ETHER
+    tristate "Ethernet packet sniffer"
+    depends on PKT_SNIFFER
+    help
+        Say Y here if you want to use the Ethernet packet sniffer
+        module by Linn Products Ltd. It can be found in the upcoming
+        Pistachio SoC by Imagination Technologies.
+
+        The driver can also be built as a module. If so, the module
+        will be called snf_ether.
+
 endif # NET_VENDOR_LINN
diff --git a/drivers/net/ethernet/linn/Makefile b/drivers/net/ethernet/linn/Makefile
index f3338f3..f51eb66 100644
--- a/drivers/net/ethernet/linn/Makefile
+++ b/drivers/net/ethernet/linn/Makefile
@@ -17,3 +17,4 @@
 ###############################################################################
 
 obj-$(CONFIG_PKT_SNIFFER) += pkt-sniffer/core/
+obj-$(CONFIG_PKT_SNIFFER_ETHER) += pkt-sniffer/backends/ether/
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile
new file mode 100644
index 0000000..1f97e51
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/Makefile
@@ -0,0 +1,20 @@
+###############################################################################
+# Makefile for the Linn ethernet packet sniffer driver
+#
+# Copyright (C) 2015 Linn Products Ltd
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# Written by:
+# Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+###############################################################################
+
+obj-$(CONFIG_PKT_SNIFFER_ETHER) += snf_ether.o
+snf_ether-objs := platform.o channel.o
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c
new file mode 100644
index 0000000..87ec790
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.c
@@ -0,0 +1,444 @@
+/*
+ * Ethernet Mii packet sniffer driver
+ *  - channel functions
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#include <linux/io.h>
+#include <linux/hrtimer.h>
+#include <linux/clocksource.h>
+#include "../../core/snf_core.h"
+#include "hw.h"
+#include "channel.h"
+
+#define to_ether_snf_chan(dev) container_of(dev, struct ether_snf_chan, chan)
+
+#define CMD_DONTCARE	0
+#define CMD_MATCH	1
+#define CMD_COPY	2
+#define CMD_MATCHSTAMP	3
+#define CMD_COPYDONE	4
+
+/* Checks if the supplied command string is compatible with the
+ * capabilities of the H/W.
+ */
+static bool validate_pattern(
+			struct ether_snf_chan *ch,
+			const u8 *buf,
+			int count)
+{
+	int i, complete, max_copy_bytes;
+	int ts = 0;
+	int copy_before = 0;
+	int copy_after = 0;
+
+	if (count > ch->max_cmds)
+		return false;
+
+	/* Iterate through the commands in the string */
+	for (i = 0, complete = 0; (i < count) && !complete; i++) {
+		u8 cmd = buf[2 * i];
+
+		switch (cmd) {
+		case CMD_DONTCARE:
+		case CMD_MATCH:
+			break;
+
+		case CMD_MATCHSTAMP:
+			/* The timestamp needs to be word-aligned in the FIFO
+			 * therefore, the number of 'copy' commands before it
+			 * needs to be a multiple of 4
+			 */
+			if (copy_before & 3)
+				return false;
+			/* Signal that a timestamp will be present */
+			ts = 1;
+			break;
+
+		case CMD_COPY:
+			/* Increment count of bytes that will be returned */
+			if (ts)
+				copy_after++;
+			else
+				copy_before++;
+			break;
+
+		case CMD_COPYDONE:
+			/* Increment count of bytes that will be returned
+			 * This command terminates the string
+			 */
+			if (ts)
+				copy_after++;
+			else
+				copy_before++;
+			/* This command completes the command string */
+			complete = 1;
+			break;
+
+		default:
+			/* Invalid command id */
+			return false;
+		}
+	}
+
+	/* Check if the string was properly terminated
+	 * and contained valid number of commands
+	 */
+	if (complete) {
+		max_copy_bytes = ch->fifo_blk_words * 4;
+		if (ts)
+			max_copy_bytes -= 4;
+		/* Too many copy commands will case the FIFO
+		 * to wrap around
+		 */
+		if ((copy_before + copy_after) > max_copy_bytes)
+			return false;
+		ch->nfb_before = copy_before;
+		ch->nfb_after = copy_after;
+		ch->evt.ts_valid = ts;
+		ch->evt.len = ch->nfb_before + ch->nfb_after;
+		return true;
+	}
+
+	/* Command string not terminated */
+	return false;
+}
+
+/* Channel methods */
+
+/* Enables the channel */
+static int esnf_start(struct snf_chan *dev)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+
+	if (!ch->started) {
+		ch->evt.ts = 0;
+		/* Enable interrupts */
+		iowrite32(ch->data_irq_bit | ch->full_irq_bit,
+			  ch->regs + SET_INTERRUPT_ENABLE);
+		/* Enable the packet matching logic */
+		iowrite32(ENABLE_BIT, ch->reg_enable);
+
+		ch->started = 1;
+		dev_info(ch->dev, "%s: started\n", ch->name);
+	} else {
+		dev_dbg(ch->dev, "%s: already running\n", ch->name);
+	}
+
+	return 0;
+}
+
+/* Disables the channel */
+static int esnf_stop(struct snf_chan *dev)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+
+	if (ch->started) {
+		/* Disable interrupts */
+		iowrite32(ch->data_irq_bit | ch->full_irq_bit,
+			  ch->regs + CLEAR_INTERRUPT_ENABLE);
+		/* Stop the sniffer channel */
+		iowrite32(0, ch->reg_enable);
+		/* Clear any pending interrupts */
+		iowrite32(ch->data_irq_bit | ch->full_irq_bit,
+			  ch->regs + INTERRUPT_STATUS);
+
+		ch->started = 0;
+		dev_info(ch->dev, "%s: stopped\n", ch->name);
+	} else {
+		dev_dbg(ch->dev, "%s: already stopped\n", ch->name);
+	}
+
+	return 0;
+}
+
+/* Sets the command string (pattern) for the channel
+ * The bytes in the pattern buffer are in the following order:
+ */
+static int esnf_set_pattern(struct snf_chan *dev, const u8 *pattern, int count)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+	int i, shift = 0;
+	u32  val = 0, *ptr;
+
+	dev_info(ch->dev, "%s: set cmd pattern with %d entries\n",
+		 ch->name, count);
+
+	if (ch->started) {
+		dev_err(ch->dev,
+			"%s: cannot apply cmd pattern. Channel is active\n",
+			ch->name);
+		return -EBUSY;
+	}
+
+	if (!validate_pattern(ch, pattern, count)) {
+		dev_err(ch->dev,
+			"%s: invalid cmd pattern\n",
+			ch->name);
+		return -EINVAL;
+	}
+
+	for (ptr = ch->cmd_ram, i = 0, shift = 24; i < (2 * count); i++) {
+		val |= ((u32)pattern[i]) << shift;
+		if (!shift) {
+			iowrite32(val, ptr++);
+			val = 0;
+			shift = 24;
+		} else {
+			shift -= 8;
+		}
+	}
+	if (shift)
+		iowrite32(val, ptr);
+
+	return 0;
+}
+
+/* Returns max number of commands supported by the channel */
+static int esnf_max_ptn_entries(struct snf_chan *dev)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+
+	return ch->max_cmds;
+}
+
+static int esnf_ts_enabled(struct snf_chan *dev)
+{
+	struct ether_snf_chan *ch = to_ether_snf_chan(dev);
+
+	return ch->evt.ts_valid;
+}
+
+/* Gray decoder */
+static u32 gray_decode(u32 gray)
+{
+	gray ^= (gray >> 16);
+	gray ^= (gray >> 8);
+	gray ^= (gray >> 4);
+	gray ^= (gray >> 2);
+	gray ^= (gray >> 1);
+	return gray;
+}
+
+/* Read a block from the data FIFO */
+static void read_fifo_data(struct ether_snf_chan *ch)
+{
+	int i;
+	u32 val, *ptr;
+	int ts = ch->evt.ts_valid;
+	int dw = ch->fifo_blk_words;
+	int bytes_before = ch->nfb_before;
+	int bytes_after = ch->nfb_after;
+
+	ptr = (u32 *)ch->evt.data;
+	for (i = 0; i < dw; i++) {
+		val = ioread32(ch->reg_fifo);
+		if (bytes_before > 0) {
+			/* Bytes before the timestamp */
+			*ptr++ = cpu_to_be32(val);
+			bytes_before -= 4;
+		} else if (ts) {
+			ch->raw_tstamp = gray_decode(val);
+			/* First timestamp since the channel was started.
+			 * Initialise the timecounter
+			 */
+			if (!ch->evt.ts)
+				timecounter_init(
+					&ch->tc,
+					&ch->cc,
+					ktime_to_ns(ktime_get_real()));
+			ch->evt.ts = timecounter_read(&ch->tc);
+			ts = 0;
+		} else if (bytes_after > 0) {
+			/* Bytes after the timestamp */
+			*ptr++ = cpu_to_be32(val);
+			bytes_after -= 4;
+		}
+	}
+}
+
+/* Read method for the timestamp cycle counter
+ * Returns the last received timestamp value
+ */
+static cycle_t esnf_cyclecounter_read(const struct cyclecounter *cc)
+{
+	struct ether_snf_chan *ch = container_of(cc, struct ether_snf_chan, cc);
+
+	return ch->raw_tstamp;
+}
+
+/* Taken from clocks_calc_mult_shift() in kernel/time/clocksource.c
+ * Unfortunately that function is not exported by the kernel
+ */
+static void esnf_clocks_calc_mult_shift(
+				u32 *mult,
+				u32 *shift,
+				u32 from,
+				u32 to,
+				u32 maxsec)
+{
+	u64 tmp;
+	u32 sft, sftacc = 32;
+
+	/* Calculate the shift factor which is limiting the conversion
+	 * range:
+	 */
+	tmp = ((u64)maxsec * from) >> 32;
+	while (tmp) {
+		tmp >>= 1;
+		sftacc--;
+	}
+
+	/* Find the conversion shift/mult pair which has the best
+	 * accuracy and fits the maxsec conversion range:
+	 */
+	for (sft = 32; sft > 0; sft--) {
+		tmp = (u64)to << sft;
+		tmp += from / 2;
+		do_div(tmp, from);
+		if ((tmp >> sftacc) == 0)
+			break;
+	}
+	*mult = tmp;
+	*shift = sft;
+}
+
+/* Follows the logic of __clocksource_updatefreq_scale() in
+ * in kernel/time/clocksource.c
+ */
+static void calc_mult_shift(u32 *mult, u32 *shift, cycle_t mask, u32 freq)
+{
+	u64 sec;
+
+	sec = mask - (mask >> 3);
+	do_div(sec, freq);
+	if (!sec)
+		sec = 1;
+	else if (sec > 600 && mask > UINT_MAX)
+		sec = 600;
+	esnf_clocks_calc_mult_shift(mult, shift, freq, NSEC_PER_SEC, sec);
+}
+
+/* Initialises a sniffer channel */
+int channel_init(
+	struct ether_snf_chan *ch,
+	struct platform_device *pdev,
+	void *regs,
+	int fifo_blk_words,
+	u32 tstamp_hz,
+	u32 tstamp_bits,
+	int tx)
+{
+	struct resource *res;
+	u32 *ptr;
+	int i;
+
+	ch->regs = regs;
+	ch->dev = &pdev->dev;
+	ch->data_irq_bit = tx ? TX_DATA_IRQ_BIT : RX_DATA_IRQ_BIT;
+	ch->full_irq_bit = tx ? TX_FULL_IRQ_BIT : RX_FULL_IRQ_BIT;
+	ch->reg_enable = ch->regs +
+			 (tx ? TX_SNIFFER_ENABLE : RX_SNIFFER_ENABLE);
+	ch->reg_fifo = ch->regs + (tx ? TX_FIFO_DAT : RX_FIFO_DAT);
+
+	/* Retrieve and remap the address space for the command memory */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   tx ? "tx-ram" : "rx-ram");
+	if (!res)
+		return -ENOSYS;
+	ch->cmd_ram = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ch->cmd_ram))
+		return PTR_ERR(ch->cmd_ram);
+
+	/* It is 2 bytes/command, hence divide by 2 */
+	ch->max_cmds = resource_size(res) / 2;
+
+	/* Initialise the command string RAM */
+	for (i = 0, ptr = ch->cmd_ram; i < resource_size(res); i += 4)
+		iowrite32((CMD_DONTCARE << 24) | (CMD_DONTCARE << 8),
+			  ptr++);
+
+	ch->fifo_blk_words = fifo_blk_words;
+	ch->started = 0;
+
+	/* Initialise the timestamp cycle counter */
+	ch->cc.read = esnf_cyclecounter_read;
+	ch->cc.mask = CLOCKSOURCE_MASK(tstamp_bits);
+	calc_mult_shift(&ch->cc.mult, &ch->cc.shift, ch->cc.mask, tstamp_hz);
+
+	/* Register the channel methods */
+	ch->chan.start = esnf_start;
+	ch->chan.stop = esnf_stop;
+	ch->chan.set_pattern = esnf_set_pattern;
+	ch->chan.max_ptn_entries = esnf_max_ptn_entries;
+	ch->chan.ts_enabled = esnf_ts_enabled;
+
+	strncpy(ch->name, tx ? "TX" : "RX", MAX_CHAN_NAME_SIZE - 1);
+
+	dev_dbg(ch->dev, "%s: channel initialized\n", ch->name);
+
+	return 0;
+}
+
+/* Registers the channel with the sniffer core module */
+int channel_register(struct ether_snf_chan *ch, const char *name)
+{
+	int ret;
+
+	ret = snf_channel_add(&ch->chan, name);
+	if (ret < 0)
+		return ret;
+
+	dev_info(ch->dev, "%s channel added\n", ch->name);
+	return 0;
+}
+
+/* Unregisters the channel */
+int channel_unregister(struct ether_snf_chan *ch)
+{
+	int ret;
+
+	ch->chan.stop(&ch->chan);
+	ret = snf_channel_remove(&ch->chan);
+	if (!ret)
+		dev_info(ch->dev, "%s channel removed\n", ch->name);
+	return ret;
+}
+
+/* Process match event data */
+void channel_data_available(struct ether_snf_chan *ch)
+{
+	int ret;
+
+	dev_dbg(ch->dev, "%s match event\n", ch->name);
+
+	read_fifo_data(ch);
+	ret = snf_channel_notify_match(&ch->chan, &ch->evt);
+	if (ret < 0)
+		dev_err(ch->dev, "%s: event notification failed\n", ch->name);
+}
+
+/* Suspend opertion */
+int channel_suspend(struct ether_snf_chan *ch)
+{
+	return snf_channel_suspend(&ch->chan);
+}
+
+/* Resume operation */
+int channel_resume(struct ether_snf_chan *ch)
+{
+	return snf_channel_resume(&ch->chan);
+}
+
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h
new file mode 100644
index 0000000..75b942e
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/channel.h
@@ -0,0 +1,80 @@
+/*
+ * Ethernet Mii packet sniffer driver
+ *  - channel interface
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#ifndef _ETHER_SNIFFER_CHANNEL_H_
+#define _ETHER_SNIFFER_CHANNEL_H_
+
+#include <linux/platform_device.h>
+#include <linux/timecounter.h>
+#include "../../core/snf_core.h"
+
+#define MAX_CHAN_NAME_SIZE 5
+
+struct ether_snf_chan {
+	/* Sniffer core structure */
+	struct snf_chan chan;
+	/* Pointer to device struct */
+	struct device *dev;
+	/* Registers */
+	u8 __iomem *regs;
+	/* Command string memory */
+	u32 __iomem *cmd_ram;
+	/* Bit number for the data IRQ */
+	int data_irq_bit;
+	/* Bit number for the FIFO full IRQ */
+	int full_irq_bit;
+	/* Channel enable register */
+	u8 __iomem *reg_enable;
+	/* Data FIFO register */
+	u8 __iomem *reg_fifo;
+	/* Max number of commands in the string */
+	int max_cmds;
+	/* Max matching bytes that can fit in a FIFO block */
+	int fifo_blk_words;
+	/* Number of bytes in the FIFO before the timestamp */
+	int nfb_before;
+	/* Number of bytes in the FIFO after the timestamp */
+	int nfb_after;
+	/* Channel active flag */
+	int started;
+	/* Last raw timestamp from the FIFO */
+	u32 raw_tstamp;
+	/* Channel name (only used by debug messages) */
+	char name[MAX_CHAN_NAME_SIZE];
+	/* Struct to hold data from a packet match */
+	struct snf_match_evt evt;
+	/* Cycle and time counters for tstamp handling */
+	struct cyclecounter cc;
+	struct timecounter tc;
+};
+
+int channel_init(
+		struct ether_snf_chan *ch,
+		struct platform_device *pdev,
+		void *regs,
+		int fifo_blk_words,
+		u32 tstamp_hz,
+		u32 tstamp_bits,
+		int tx);
+int channel_register(struct ether_snf_chan *ch, const char *name);
+int channel_unregister(struct ether_snf_chan *ch);
+void channel_data_available(struct ether_snf_chan *ch);
+int channel_suspend(struct ether_snf_chan *ch);
+int channel_resume(struct ether_snf_chan *ch);
+
+#endif
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h
new file mode 100644
index 0000000..edb1093
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/hw.h
@@ -0,0 +1,46 @@
+/*
+ * Ethernet Mii packet sniffer driver
+ *  - register map
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#ifndef _ETHER_SNIFFER_HW_H_
+#define _ETHER_SNIFFER_HW_H_
+
+#include <linux/bitops.h>
+
+/* Registers */
+#define INTERRUPT_ENABLE        0x00
+#define SET_INTERRUPT_ENABLE    0x04
+#define CLEAR_INTERRUPT_ENABLE  0x08
+#define INTERRUPT_STATUS        0x0c
+#define TX_FIFO_DAT             0x10
+#define RX_FIFO_DAT             0x14
+#define TX_FIFO_OCC             0x18
+#define RX_FIFO_OCC             0x1c
+#define TX_SNIFFER_ENABLE       0x20
+#define RX_SNIFFER_ENABLE       0x24
+
+/* IRQ register bits */
+#define TX_DATA_IRQ_BIT         BIT(0)
+#define RX_DATA_IRQ_BIT         BIT(1)
+#define TX_FULL_IRQ_BIT         BIT(2)
+#define RX_FULL_IRQ_BIT         BIT(3)
+
+/* Enable register bits */
+#define ENABLE_BIT              BIT(0)
+
+#endif
+
diff --git a/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c
new file mode 100644
index 0000000..4da039a
--- /dev/null
+++ b/drivers/net/ethernet/linn/pkt-sniffer/backends/ether/platform.c
@@ -0,0 +1,318 @@
+/*
+ * This module is the driver for the Linn Ethernet Mii packet sniffer
+ * H/W module. It allows incoming and outoing Ethernet packets to be
+ * parsed, matched against a user-defined pattern and timestamped.
+ * It sits between an Ethernet MAC and PHY and is completely passive
+ * with respect to Ethernet frames.
+ *
+ * Packet filtering is driven by a user-supplied command string
+ * which consists of a series of interleaved command and data bytes.
+ * ie. the command string has the following format:
+ *  --------------------------------
+ *  | CMD | DATA | CMD | DATA | ....
+ *  --------------------------------
+ * The following commands are supported:
+ * 0 - Don't care
+ * 1 - Match: packet data must match command string byte
+ * 2 - Copy: packet data will be copied to FIFO
+ * 3 - Match/Stamp: if packet data matches string byte, a timestamp
+ *                  is copied into the FIFO
+ * 4 - Copy/Done: packet data will be copied into the FIFO.
+ *                This command terminates the command string.
+ * Example:
+ *   0x00, 0x00, 0x01, 0xDE, 0x03, 0x20, 0x04, 0x00
+ *   The above string will match Ethernet packets where the 2nd and 3rd
+ *   bytes of the destination MAC address are 0xDE and 0x22.
+ *   For each matched packet a timestamp and the 4th byte of the destination
+ *   MAC will be copied to the FIFO
+ *
+ * - An IRQ is triggered for every packet match event
+ * - The modules includes a H/W block based FIFO where matched packet data
+ *   and timestamp values are placed
+ * - The FIFO is accessed through a single register
+ * - An IRQ is also generated if all FIFO blocks are filled.
+ * - Timestamps are Gray encoded
+ *
+ * Copyright (C) 2015 Linn Products Ltd
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Stathis Voukelatos <stathis.voukelatos@linn.co.uk>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include "../../core/snf_core.h"
+#include "hw.h"
+#include "channel.h"
+
+/* Names for the TX and RX channel net interfaces */
+static const char tx_channel_name[] = "snfethtx%d";
+static const char rx_channel_name[] = "snfethrx%d";
+
+struct ether_snf {
+	u8 __iomem *regs;
+	int irq;
+	struct clk *sys_clk;
+	struct clk *ts_clk;
+	struct ether_snf_chan txc;
+	struct ether_snf_chan rxc;
+};
+
+/* Interrupt handler */
+static irqreturn_t esnf_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = (struct platform_device *)dev_id;
+	struct ether_snf *esnf = (struct ether_snf *)platform_get_drvdata(pdev);
+	u32 irq_status;
+
+	if (unlikely(esnf->irq != irq))
+		return IRQ_NONE;
+
+	irq_status = ioread32(esnf->regs + INTERRUPT_STATUS) &
+				 ioread32(esnf->regs + INTERRUPT_ENABLE);
+
+	dev_dbg(&pdev->dev, "irq: 0x%08x\n", irq_status);
+
+	/* TX FIFO full */
+	if (unlikely(irq_status & TX_FULL_IRQ_BIT))
+		dev_notice(&pdev->dev, "TX FIFO full\n");
+
+	/* RX FIFO full */
+	if (unlikely(irq_status & RX_FULL_IRQ_BIT))
+		dev_notice(&pdev->dev, "RX FIFO full\n");
+
+	/* TX match data available */
+	if (irq_status & TX_DATA_IRQ_BIT) {
+		dev_dbg(&pdev->dev, "TX data\n");
+		channel_data_available(&esnf->txc);
+	}
+
+	/* RX match data available */
+	if (irq_status & RX_DATA_IRQ_BIT) {
+		dev_dbg(&pdev->dev, "RX data\n");
+		channel_data_available(&esnf->rxc);
+	}
+
+	/* Clear interrupts */
+	iowrite32(irq_status, esnf->regs + INTERRUPT_STATUS);
+
+	return IRQ_HANDLED;
+}
+
+/* Called when the packet sniffer device is bound with the driver */
+static int esnf_driver_probe(struct platform_device *pdev)
+{
+	struct ether_snf *esnf;
+	struct resource *res;
+	int ret, irq;
+	u32 fifo_blk_words, ts_hz, ts_bits;
+	void __iomem *regs;
+	struct device_node *ofn = pdev->dev.of_node;
+
+	/* Allocate the device data structure */
+	esnf = devm_kzalloc(&pdev->dev, sizeof(*esnf), GFP_KERNEL);
+	if (!esnf)
+		return -ENOMEM;
+
+	/* Retrieve and remap register memory space */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+	esnf->regs = regs;
+
+	if (!ofn)
+		return -ENODEV;
+
+	/* Read requirede properties from the device tree node */
+	ret = of_property_read_u32(
+				ofn,
+				"fifo-block-words",
+				&fifo_blk_words);
+	if (ret < 0)
+		return ret;
+
+	if (((fifo_blk_words - 1) * 4) > MAX_MATCH_BYTES) {
+		dev_err(&pdev->dev,
+			"Invalid FIFO block size entry in device tree\n");
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32(
+				ofn,
+				"tstamp-bits",
+				&ts_bits);
+	if (ret < 0)
+		return ret;
+
+	/* Enable peripheral bus and timstamp clocks */
+	esnf->sys_clk = devm_clk_get(&pdev->dev, "sys");
+	if (IS_ERR(esnf->sys_clk)) {
+		ret = PTR_ERR(esnf->sys_clk);
+		return ret;
+	}
+	ret = clk_prepare_enable(esnf->sys_clk);
+	if (ret < 0)
+		return ret;
+
+	esnf->ts_clk = devm_clk_get(&pdev->dev, "tstamp");
+	if (IS_ERR(esnf->ts_clk)) {
+		ret = PTR_ERR(esnf->ts_clk);
+		goto fail1;
+	}
+	ret = clk_prepare_enable(esnf->ts_clk);
+	if (ret < 0)
+		goto fail1;
+
+	/* Initialise the TX and RX channels */
+	ts_hz = clk_get_rate(esnf->ts_clk);
+	ret = channel_init(
+			&esnf->txc,
+			pdev,
+			regs,
+			fifo_blk_words,
+			ts_hz,
+			ts_bits,
+			1);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to init TX channel (%d)\n", ret);
+		goto fail2;
+	}
+	ret = channel_init(
+			&esnf->rxc,
+			pdev,
+			regs,
+			fifo_blk_words,
+			ts_hz,
+			ts_bits,
+			0);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to init RX channel (%d)\n", ret);
+		goto fail2;
+	}
+
+	/* Register the channels with the sniffer core module */
+	ret = channel_register(&esnf->txc, tx_channel_name);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register TX chan (%d)\n", ret);
+		goto fail2;
+	}
+	ret = channel_register(&esnf->rxc, rx_channel_name);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register RX chan (%d)\n", ret);
+		goto fail3;
+	}
+
+	platform_set_drvdata(pdev, esnf);
+
+	/* Register the interrupt handler */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		goto fail4;
+	esnf->irq = irq;
+	ret = devm_request_irq(
+			&pdev->dev,
+			irq,
+			esnf_interrupt,
+			0,
+			KBUILD_MODNAME,
+			pdev);
+	if (ret < 0)
+		goto fail4;
+
+	return 0;
+
+fail4:
+	channel_unregister(&esnf->rxc);
+fail3:
+	channel_unregister(&esnf->txc);
+fail2:
+	clk_disable_unprepare(esnf->ts_clk);
+fail1:
+	clk_disable_unprepare(esnf->sys_clk);
+	return ret;
+}
+
+/* Called when the packet sniffer device unregisters with the driver */
+static int esnf_driver_remove(struct platform_device *pdev)
+{
+	struct ether_snf *esnf = (struct ether_snf *)platform_get_drvdata(pdev);
+	int ret;
+
+	ret = channel_unregister(&esnf->txc);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to unregister TX chan (%d)\n", ret);
+		return ret;
+	}
+	ret = channel_unregister(&esnf->rxc);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to unregister RX chan (%d)\n", ret);
+		return ret;
+	}
+	clk_disable_unprepare(esnf->ts_clk);
+	clk_disable_unprepare(esnf->sys_clk);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/* Driver suspend method */
+static int esnf_driver_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ether_snf *esnf = (struct ether_snf *)platform_get_drvdata(pdev);
+
+	channel_suspend(&esnf->txc);
+	channel_suspend(&esnf->rxc);
+	return 0;
+}
+
+/* Driver resume method */
+static int esnf_driver_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ether_snf *esnf = (struct ether_snf *)platform_get_drvdata(pdev);
+
+	channel_resume(&esnf->txc);
+	channel_resume(&esnf->rxc);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(esnf_pm_ops, esnf_driver_suspend, esnf_driver_resume);
+#endif
+
+static const struct of_device_id esnf_of_match_table[] = {
+	{ .compatible = "linn,eth-packet-sniffer" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, esnf_of_match_table);
+
+static struct platform_driver esnf_platform_driver = {
+	.driver = {
+		.name           = KBUILD_MODNAME,
+#ifdef CONFIG_PM
+		.pm	        = &esnf_pm_ops,
+#endif
+		.of_match_table = esnf_of_match_table,
+	},
+	.probe = esnf_driver_probe,
+	.remove = esnf_driver_remove,
+};
+
+module_platform_driver(esnf_platform_driver);
+
+MODULE_DESCRIPTION("Linn Ethernet Packet Sniffer");
+MODULE_AUTHOR("Linn Products Ltd");
+MODULE_LICENSE("GPL v2");
+
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
  2015-02-24 16:48 ` Stathis Voukelatos
                   ` (3 preceding siblings ...)
  (?)
@ 2015-02-25 15:19 ` Richard Cochran
  2015-02-25 17:01   ` Richard Cochran
  -1 siblings, 1 reply; 26+ messages in thread
From: Richard Cochran @ 2015-02-25 15:19 UTC (permalink / raw)
  To: Stathis Voukelatos; +Cc: linux-kernel, netdev, devicetree

On Tue, Feb 24, 2015 at 04:48:08PM +0000, Stathis Voukelatos wrote:
> This patch adds support for the Ethernet Packet Sniffer H/W module
> developed by Linn Products Ltd and found in the IMG Pistachio SoC.
> The module allows Ethernet packets to be parsed, matched against
> a user-defined pattern and timestamped. It sits between a 100M
> Ethernet MAC and PHY and is completely passive with respect to
> Ethernet frames.

First off, please stop calling this device a "sniffer".  Real sniffers
are able to deliver whole frames.  Real sniffers are most commonly
used to inspect traffic between two or more nodes, but from a third
host.

Instead, this device really is a time stamping unit with a
programmable frame matching engine.  So, the approach of this driver
is totally wrong.  It runs contrary to how time stamping is handled in
the kernel.

- This driver delivers time stamps "out of band" from a separate
  interface.  The other kernel drivers deliver time stamps "in band",
  using the same socket from the requesting process.

- This driver requires user space to match time stamps with packets.
  The other kernel drivers perform the matching automatically.

- This driver requires user space to program a vendor specific
  matching engine.  The other kernel drivers program their matching
  engines automatically.

Let me suggest another approach that stays in line with the existing
frame work.  Based on the device's limitations and your own example,
it seems clear that the intended use case is synchronization for AVB
applications using gPTP.

Your time stamping unit is conceptually the same a PHY with hardware
time stamping, and you should treat it as such.  This means using the
CONFIG_NETWORK_PHY_TIMESTAMPING kernel option.  There is one mainline
PHY driver as an example, dp83640.c.

You will have to hard code command strings in the driver, one for each
of the SIOCSHWTSTAMP filter types that you want to support.  I would
recommend supporting just HWTSTAMP_FILTER_PTP_V2_EVENT.  You will
probably need different filters for L2, IPv4, and IPv6, with and
without VLAN.  For the transmit case, you can limit the match to PTP
events as well.  Your filters should at least return the sequenceId
and the messageType back to the driver.

The only (small) difficulty I can see would be how to arrange for your
driver to be called back just like a PHY driver would be.  We might
need to adapt or expand the internal PHY timestamping framework within
the kernel, but if you are willing to rework your driver, then I can
help with that part.

Thanks,
Richard


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
  2015-02-25 15:19 ` [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver Richard Cochran
@ 2015-02-25 17:01   ` Richard Cochran
  2015-02-25 17:12       ` Stathis Voukelatos
  0 siblings, 1 reply; 26+ messages in thread
From: Richard Cochran @ 2015-02-25 17:01 UTC (permalink / raw)
  To: Stathis Voukelatos; +Cc: linux-kernel, netdev, devicetree

On Wed, Feb 25, 2015 at 04:19:45PM +0100, Richard Cochran wrote:
> Let me suggest another approach that stays in line with the existing
> frame work.  Based on the device's limitations and your own example,
> it seems clear that the intended use case is synchronization for AVB
> applications using gPTP.

Also, forgot to say, expose your clock as a PTP Hardware Clock (PHC).

Thanks,
Richard

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-02-25 17:12       ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-25 17:12 UTC (permalink / raw)
  To: Richard Cochran; +Cc: linux-kernel, netdev, devicetree

Hi Richard,

On 25/02/15 17:01, Richard Cochran wrote:
> On Wed, Feb 25, 2015 at 04:19:45PM +0100, Richard Cochran wrote:
>> Let me suggest another approach that stays in line with the existing
>> frame work.  Based on the device's limitations and your own example,
>> it seems clear that the intended use case is synchronization for AVB
>> applications using gPTP.
>
> Also, forgot to say, expose your clock as a PTP Hardware Clock (PHC).
>

Regarding this last point, the actual counter that generates the 
timestamps is not part of the sniffer H/W module. Timestamps are 
provided to the sniffer externally in H/W by a different module.
Apart of that there is not eg. a sniffer register to read the current 
counter value. I wonder if it should be the driver for the module where 
the counter belongs (called Event Timer in the Pistachio Soc) that 
should register the PHC.

I need some more time to study your other suggestions regarding the PHY 
timestamping framework.

> Thanks,
> Richard
>

Regards,
Stathis

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-02-25 17:12       ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-25 17:12 UTC (permalink / raw)
  To: Richard Cochran
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Richard,

On 25/02/15 17:01, Richard Cochran wrote:
> On Wed, Feb 25, 2015 at 04:19:45PM +0100, Richard Cochran wrote:
>> Let me suggest another approach that stays in line with the existing
>> frame work.  Based on the device's limitations and your own example,
>> it seems clear that the intended use case is synchronization for AVB
>> applications using gPTP.
>
> Also, forgot to say, expose your clock as a PTP Hardware Clock (PHC).
>

Regarding this last point, the actual counter that generates the 
timestamps is not part of the sniffer H/W module. Timestamps are 
provided to the sniffer externally in H/W by a different module.
Apart of that there is not eg. a sniffer register to read the current 
counter value. I wonder if it should be the driver for the module where 
the counter belongs (called Event Timer in the Pistachio Soc) that 
should register the PHC.

I need some more time to study your other suggestions regarding the PHY 
timestamping framework.

> Thanks,
> Richard
>

Regards,
Stathis
--
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

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-02-25 17:12       ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-25 17:12 UTC (permalink / raw)
  To: Richard Cochran
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Richard,

On 25/02/15 17:01, Richard Cochran wrote:
> On Wed, Feb 25, 2015 at 04:19:45PM +0100, Richard Cochran wrote:
>> Let me suggest another approach that stays in line with the existing
>> frame work.  Based on the device's limitations and your own example,
>> it seems clear that the intended use case is synchronization for AVB
>> applications using gPTP.
>
> Also, forgot to say, expose your clock as a PTP Hardware Clock (PHC).
>

Regarding this last point, the actual counter that generates the 
timestamps is not part of the sniffer H/W module. Timestamps are 
provided to the sniffer externally in H/W by a different module.
Apart of that there is not eg. a sniffer register to read the current 
counter value. I wonder if it should be the driver for the module where 
the counter belongs (called Event Timer in the Pistachio Soc) that 
should register the PHC.

I need some more time to study your other suggestions regarding the PHY 
timestamping framework.

> Thanks,
> Richard
>

Regards,
Stathis
--
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

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
  2015-02-25 17:12       ` Stathis Voukelatos
  (?)
  (?)
@ 2015-02-25 17:30       ` Richard Cochran
  2015-02-27 17:22           ` Stathis Voukelatos
       [not found]         ` <54F0A4C4.3020407@linn.co.uk>
  -1 siblings, 2 replies; 26+ messages in thread
From: Richard Cochran @ 2015-02-25 17:30 UTC (permalink / raw)
  To: Stathis Voukelatos; +Cc: linux-kernel, netdev, devicetree

On Wed, Feb 25, 2015 at 05:12:08PM +0000, Stathis Voukelatos wrote:
> Regarding this last point, the actual counter that generates the
> timestamps is not part of the sniffer H/W module. Timestamps are
> provided to the sniffer externally in H/W by a different module.
> Apart of that there is not eg. a sniffer register to read the
> current counter value. I wonder if it should be the driver for the
> module where the counter belongs (called Event Timer in the
> Pistachio Soc) that should register the PHC.

It is okay to have the PHC come from another driver.  However, you do
need to export PHC index to the time stamping code, in order to
provide the 'phc_index' field for the ETHTOOL_GET_TS_INFO request.

You can also have one SW driver cover both HW modules, if that is
cleaner and easier.  Among all the other drivers, only gianfar has the
PHC separate.

> I need some more time to study your other suggestions regarding the
> PHY timestamping framework.

>From my (limited) understanding of your HW device, I should think that
it will work.  The PHY time stamping subsystem is not the most obvious
code in the world.  Please feel free to ask if you have any questions.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
  2015-02-25 17:30       ` Richard Cochran
@ 2015-02-27 17:22           ` Stathis Voukelatos
       [not found]         ` <54F0A4C4.3020407@linn.co.uk>
  1 sibling, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-27 17:22 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree

Hi Richard,

On 25/02/15 17:30, Richard Cochran wrote:
>> I need some more time to study your other suggestions regarding the
>> PHY timestamping framework.
>
>  From my (limited) understanding of your HW device, I should think that
> it will work.  The PHY time stamping subsystem is not the most obvious
> code in the world.  Please feel free to ask if you have any questions.
>

To summarize (and confirm my understanding) your suggestion is for the
sniffer to be configured to match PTP packets and (similarly to the
dp83640) return the Message Type and Sequence Id fields that will allow
them to be matched to an sk_buf that has been passed from the stack.
Then the sk_buf can be timestamped using the sniffer timestamp.

The H/W does have the capability to do that. However, in order to
implement it there will be some architectural changes needed
in the kernel. This module cannot really pretend to be a PHY.
In the real world it sits between the MAC and the PHY.

> Thanks,
> Richard
>

Thanks,
Stathis

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-02-27 17:22           ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-02-27 17:22 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree

Hi Richard,

On 25/02/15 17:30, Richard Cochran wrote:
>> I need some more time to study your other suggestions regarding the
>> PHY timestamping framework.
>
>  From my (limited) understanding of your HW device, I should think that
> it will work.  The PHY time stamping subsystem is not the most obvious
> code in the world.  Please feel free to ask if you have any questions.
>

To summarize (and confirm my understanding) your suggestion is for the
sniffer to be configured to match PTP packets and (similarly to the
dp83640) return the Message Type and Sequence Id fields that will allow
them to be matched to an sk_buf that has been passed from the stack.
Then the sk_buf can be timestamped using the sniffer timestamp.

The H/W does have the capability to do that. However, in order to
implement it there will be some architectural changes needed
in the kernel. This module cannot really pretend to be a PHY.
In the real world it sits between the MAC and the PHY.

> Thanks,
> Richard
>

Thanks,
Stathis

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-02-27 18:14             ` Richard Cochran
  0 siblings, 0 replies; 26+ messages in thread
From: Richard Cochran @ 2015-02-27 18:14 UTC (permalink / raw)
  To: Stathis Voukelatos; +Cc: linux-kernel, netdev, devicetree

On Fri, Feb 27, 2015 at 05:09:24PM +0000, Stathis Voukelatos wrote:
> To summarize (and confirm my understanding) your suggestion is for the
> sniffer to be configured to match PTP packets and (similarly to the
> dp83640) return the Message Type and Sequence Id fields that will allow
> them to be matched to an sk_buf that has been passed from the stack.
> Then the sk_buf can be timestamped using the sniffer timestamp.

Yes.
 
> The H/W does have the capability to do that. However, in order to
> implement it there will be some architectural changes needed
> in the kernel. This module cannot really pretend to be a PHY.
> In the real world it sits between the MAC and the PHY.

Right.

Here is one idea.  Put a link to the TS device in the PHY's DT node.
Then, in phy_probe, check if the PHY's four methods, ts_info,
hwtstamp, rxtstamp, and txtstamp, are all null.  If so, check for a DT
link from the PHY's node to a TS device driver.  If found, then set
the four methods to call into the TS driver's callbacks.

Just off of the top of my head.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-02-27 18:14             ` Richard Cochran
  0 siblings, 0 replies; 26+ messages in thread
From: Richard Cochran @ 2015-02-27 18:14 UTC (permalink / raw)
  To: Stathis Voukelatos
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Feb 27, 2015 at 05:09:24PM +0000, Stathis Voukelatos wrote:
> To summarize (and confirm my understanding) your suggestion is for the
> sniffer to be configured to match PTP packets and (similarly to the
> dp83640) return the Message Type and Sequence Id fields that will allow
> them to be matched to an sk_buf that has been passed from the stack.
> Then the sk_buf can be timestamped using the sniffer timestamp.

Yes.
 
> The H/W does have the capability to do that. However, in order to
> implement it there will be some architectural changes needed
> in the kernel. This module cannot really pretend to be a PHY.
> In the real world it sits between the MAC and the PHY.

Right.

Here is one idea.  Put a link to the TS device in the PHY's DT node.
Then, in phy_probe, check if the PHY's four methods, ts_info,
hwtstamp, rxtstamp, and txtstamp, are all null.  If so, check for a DT
link from the PHY's node to a TS device driver.  If found, then set
the four methods to call into the TS driver's callbacks.

Just off of the top of my head.

Thanks,
Richard
--
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

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-03-06 13:45               ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-03-06 13:45 UTC (permalink / raw)
  To: linux-kernel, netdev, devicetree


Hi Richard,

On 27/02/15 18:14, Richard Cochran wrote:
 >> The H/W does have the capability to do that. However, in order to
 >> implement it there will be some architectural changes needed
 >> in the kernel. This module cannot really pretend to be a PHY.
 >> In the real world it sits between the MAC and the PHY.
 >
 > Right.
 >
 > Here is one idea.  Put a link to the TS device in the PHY's DT node.
 > Then, in phy_probe, check if the PHY's four methods, ts_info,
 > hwtstamp, rxtstamp, and txtstamp, are all null.  If so, check for a DT
 > link from the PHY's node to a TS device driver.  If found, then set
 > the four methods to call into the TS driver's callbacks.
 >
 > Just off of the top of my head.
 >

Thank you for your help and suggestions.

Although the PTP way appears to be the best from an architectural point
of view, we have some questions as whether it is suitable for the audio
use cases that this module is mainly intended for.
To use the PTP terminology in a large installation we would have a
potentially large number of clock domains.
It is not clear how to easily manage the creation and allocation of 
domains. In addition the clock will be pulled according to the audio
stream and it would be undesirable for other unrelated PTPv2 devices
on the network to join the clock domain and have their clocks 
synchronized to it.

The patch in its current form would allow a move to Linux using our
existing synchronization protocols (which are open-source). A move
to PTP is something to consider but will involve a fair amount of
redesign including upgrade of legacy products.


 > Thanks,
 > Richard
 >

Thank you,
Stathis

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-03-06 13:45               ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-03-06 13:45 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA


Hi Richard,

On 27/02/15 18:14, Richard Cochran wrote:
 >> The H/W does have the capability to do that. However, in order to
 >> implement it there will be some architectural changes needed
 >> in the kernel. This module cannot really pretend to be a PHY.
 >> In the real world it sits between the MAC and the PHY.
 >
 > Right.
 >
 > Here is one idea.  Put a link to the TS device in the PHY's DT node.
 > Then, in phy_probe, check if the PHY's four methods, ts_info,
 > hwtstamp, rxtstamp, and txtstamp, are all null.  If so, check for a DT
 > link from the PHY's node to a TS device driver.  If found, then set
 > the four methods to call into the TS driver's callbacks.
 >
 > Just off of the top of my head.
 >

Thank you for your help and suggestions.

Although the PTP way appears to be the best from an architectural point
of view, we have some questions as whether it is suitable for the audio
use cases that this module is mainly intended for.
To use the PTP terminology in a large installation we would have a
potentially large number of clock domains.
It is not clear how to easily manage the creation and allocation of 
domains. In addition the clock will be pulled according to the audio
stream and it would be undesirable for other unrelated PTPv2 devices
on the network to join the clock domain and have their clocks 
synchronized to it.

The patch in its current form would allow a move to Linux using our
existing synchronization protocols (which are open-source). A move
to PTP is something to consider but will involve a fair amount of
redesign including upgrade of legacy products.


 > Thanks,
 > Richard
 >

Thank you,
Stathis
--
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

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-03-06 13:45               ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-03-06 13:45 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA


Hi Richard,

On 27/02/15 18:14, Richard Cochran wrote:
 >> The H/W does have the capability to do that. However, in order to
 >> implement it there will be some architectural changes needed
 >> in the kernel. This module cannot really pretend to be a PHY.
 >> In the real world it sits between the MAC and the PHY.
 >
 > Right.
 >
 > Here is one idea.  Put a link to the TS device in the PHY's DT node.
 > Then, in phy_probe, check if the PHY's four methods, ts_info,
 > hwtstamp, rxtstamp, and txtstamp, are all null.  If so, check for a DT
 > link from the PHY's node to a TS device driver.  If found, then set
 > the four methods to call into the TS driver's callbacks.
 >
 > Just off of the top of my head.
 >

Thank you for your help and suggestions.

Although the PTP way appears to be the best from an architectural point
of view, we have some questions as whether it is suitable for the audio
use cases that this module is mainly intended for.
To use the PTP terminology in a large installation we would have a
potentially large number of clock domains.
It is not clear how to easily manage the creation and allocation of 
domains. In addition the clock will be pulled according to the audio
stream and it would be undesirable for other unrelated PTPv2 devices
on the network to join the clock domain and have their clocks 
synchronized to it.

The patch in its current form would allow a move to Linux using our
existing synchronization protocols (which are open-source). A move
to PTP is something to consider but will involve a fair amount of
redesign including upgrade of legacy products.


 > Thanks,
 > Richard
 >

Thank you,
Stathis
--
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

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
       [not found]             ` <54F98660.5070805@linn.co.uk>
@ 2015-03-06 15:22               ` Richard Cochran
  2015-03-11 11:20                   ` Stathis Voukelatos
  0 siblings, 1 reply; 26+ messages in thread
From: Richard Cochran @ 2015-03-06 15:22 UTC (permalink / raw)
  To: Stathis Voukelatos; +Cc: linux-kernel, netdev, devicetree

On Fri, Mar 06, 2015 at 10:50:08AM +0000, Stathis Voukelatos wrote:
> Although the PTP way appears to be the best from an architectural point
> of view, we have some questions as whether it is suitable for the audio
> use cases that this module is mainly intended for.
> To use the PTP terminology in a large installation we would have a
> potentially large number of clock domains.
> It is not clear how to easily manage the creation and allocation of
> domains. In addition the clock will be pulled according to the audio
> stream and it would be undesirable for other unrelated PTPv2 devices
> on the network to join the clock domain and have their clocks
> synchronized to it.

I don't really know what the problem here is.  Yes, there is some
networking configuration that you need to do when administering a
network using PTP protocols.  But these protocols (1588 aka PTP, and
802.1AS aka gPTP) do offer means for dealing with this.  In
particular, there is no danger mixing 1588 devices with audio devices,
because the gPTP protocol uses a different transport flag.

In any case, this has nothing at all to do with the kernel interface.
 
> The patch in its current form would allow a move to Linux using our
> existing synchronization protocols (which are open-source). A move
> to PTP is something to consider but will involve a fair amount of
> redesign including upgrade of legacy products.

If you want to try and integrate your custom protocols into the
networking stack, by all means please post them.  I would certainly
support expanding the time stamping interface to include your
protocol's packet types (like adding them to hwtstamp_rx_filters).
Maybe that would be enough for you?

Thanks,
Richard

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
  2015-03-06 13:45               ` Stathis Voukelatos
  (?)
  (?)
@ 2015-03-06 15:24               ` Richard Cochran
  -1 siblings, 0 replies; 26+ messages in thread
From: Richard Cochran @ 2015-03-06 15:24 UTC (permalink / raw)
  To: Stathis Voukelatos; +Cc: linux-kernel, netdev, devicetree

BTW I am getting doubles of your messages, both addressed to the
mailings lists, but only one also addressed to me.  You should just
send one copy, with everyone on CC.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
  2015-03-06 15:22               ` Richard Cochran
@ 2015-03-11 11:20                   ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-03-11 11:20 UTC (permalink / raw)
  To: Richard Cochran; +Cc: linux-kernel, netdev, devicetree

Hi Richard,

On 06/03/15 15:22, Richard Cochran wrote:
> I don't really know what the problem here is.  Yes, there is some
> networking configuration that you need to do when administering a
> network using PTP protocols.  But these protocols (1588 aka PTP, and
> 802.1AS aka gPTP) do offer means for dealing with this.  In
> particular, there is no danger mixing 1588 devices with audio devices,
> because the gPTP protocol uses a different transport flag.
>
> In any case, this has nothing at all to do with the kernel interface.

Our feeling is that we will have to test and verify that a move to gPTP
will fit with the use cases that we have to support and that will
require a fair amount of effort and rewrite of application software.
If the driver is not acceptable with the current interface we may need
to maintain it as a private patch until we are ready to move to gPTP
as you recommend.

>
> If you want to try and integrate your custom protocols into the
> networking stack, by all means please post them.  I would certainly
> support expanding the time stamping interface to include your
> protocol's packet types (like adding them to hwtstamp_rx_filters).
> Maybe that would be enough for you?

I was referring to the Songcast protocol we are using which is part
of the OpenHome suite (www.openhome.org) and runs on top of UDP.
It could be filtered by testing the first 5 bytes of the payload.
In our implementation we also add the destination IP and port to
the filter to make it more reliable, but hwtstamp_rx_filters cannot
accept parameters. However, I will test that and maybe come back with
a patch to expand the hwtstamp_rx_filter enum initially?

>
> Thanks,
> Richard
>

Thank you,
Stathis

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
@ 2015-03-11 11:20                   ` Stathis Voukelatos
  0 siblings, 0 replies; 26+ messages in thread
From: Stathis Voukelatos @ 2015-03-11 11:20 UTC (permalink / raw)
  To: Richard Cochran; +Cc: linux-kernel, netdev, devicetree

Hi Richard,

On 06/03/15 15:22, Richard Cochran wrote:
> I don't really know what the problem here is.  Yes, there is some
> networking configuration that you need to do when administering a
> network using PTP protocols.  But these protocols (1588 aka PTP, and
> 802.1AS aka gPTP) do offer means for dealing with this.  In
> particular, there is no danger mixing 1588 devices with audio devices,
> because the gPTP protocol uses a different transport flag.
>
> In any case, this has nothing at all to do with the kernel interface.

Our feeling is that we will have to test and verify that a move to gPTP
will fit with the use cases that we have to support and that will
require a fair amount of effort and rewrite of application software.
If the driver is not acceptable with the current interface we may need
to maintain it as a private patch until we are ready to move to gPTP
as you recommend.

>
> If you want to try and integrate your custom protocols into the
> networking stack, by all means please post them.  I would certainly
> support expanding the time stamping interface to include your
> protocol's packet types (like adding them to hwtstamp_rx_filters).
> Maybe that would be enough for you?

I was referring to the Songcast protocol we are using which is part
of the OpenHome suite (www.openhome.org) and runs on top of UDP.
It could be filtered by testing the first 5 bytes of the payload.
In our implementation we also add the destination IP and port to
the filter to make it more reliable, but hwtstamp_rx_filters cannot
accept parameters. However, I will test that and maybe come back with
a patch to expand the hwtstamp_rx_filter enum initially?

>
> Thanks,
> Richard
>

Thank you,
Stathis

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver
  2015-03-11 11:20                   ` Stathis Voukelatos
  (?)
@ 2015-03-11 15:03                   ` Richard Cochran
  -1 siblings, 0 replies; 26+ messages in thread
From: Richard Cochran @ 2015-03-11 15:03 UTC (permalink / raw)
  To: Stathis Voukelatos; +Cc: linux-kernel, netdev, devicetree

On Wed, Mar 11, 2015 at 11:20:59AM +0000, Stathis Voukelatos wrote:
> Our feeling is that we will have to test and verify that a move to gPTP
> will fit with the use cases that we have to support and that will
> require a fair amount of effort and rewrite of application software.
> If the driver is not acceptable with the current interface we may need
> to maintain it as a private patch until we are ready to move to gPTP
> as you recommend.

Sure, there is nothing wrong with that.  For the kernel, we want to
build good interfaces for future applications.  Sometimes reworking
the applications that use the old, private interfaces is just too much
work, so you have to maintain those interfaces in your products.

> I was referring to the Songcast protocol we are using which is part
> of the OpenHome suite (www.openhome.org) and runs on top of UDP.
> It could be filtered by testing the first 5 bytes of the payload.

Sounds promising.

> In our implementation we also add the destination IP and port to
> the filter to make it more reliable, but hwtstamp_rx_filters cannot
> accept parameters.

If the IP is a defined multicast group address, and if the port is
well a known port, then you should of course include them in the
driver level filter.

Adding a unicast destination IP doesn't make it more reliable, because
frames addressed to other hosts are switched away from the host (or
dropped by the MAC).

> However, I will test that and maybe come back with
> a patch to expand the hwtstamp_rx_filter enum initially?

It probably makes more sense to present the expanded filter list in
the same patch series with the new driver that uses it, in order to
see the context.  So I would hold off posting until both are ready.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2015-03-11 15:03 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-24 16:48 [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver Stathis Voukelatos
2015-02-24 16:48 ` Stathis Voukelatos
2015-02-24 16:48 ` [PATCH net-next v4 1/3] Linn Ethernet packet sniffer: device tree binding and vendor prefix Stathis Voukelatos
2015-02-24 16:48   ` Stathis Voukelatos
2015-02-24 16:48 ` [PATCH net-next v4 2/3] Linn packet sniffer core framework Stathis Voukelatos
2015-02-24 16:48   ` Stathis Voukelatos
2015-02-24 16:48 ` [PATCH net-next v4 3/3] Linn Ethernet packet sniffer driver Stathis Voukelatos
2015-02-24 16:48   ` Stathis Voukelatos
2015-02-25 15:19 ` [PATCH net-next v4 0/3] Linn Ethernet Packet Sniffer driver Richard Cochran
2015-02-25 17:01   ` Richard Cochran
2015-02-25 17:12     ` Stathis Voukelatos
2015-02-25 17:12       ` Stathis Voukelatos
2015-02-25 17:12       ` Stathis Voukelatos
2015-02-25 17:30       ` Richard Cochran
2015-02-27 17:22         ` Stathis Voukelatos
2015-02-27 17:22           ` Stathis Voukelatos
     [not found]         ` <54F0A4C4.3020407@linn.co.uk>
2015-02-27 18:14           ` Richard Cochran
2015-02-27 18:14             ` Richard Cochran
2015-03-06 13:45             ` Stathis Voukelatos
2015-03-06 13:45               ` Stathis Voukelatos
2015-03-06 13:45               ` Stathis Voukelatos
2015-03-06 15:24               ` Richard Cochran
     [not found]             ` <54F98660.5070805@linn.co.uk>
2015-03-06 15:22               ` Richard Cochran
2015-03-11 11:20                 ` Stathis Voukelatos
2015-03-11 11:20                   ` Stathis Voukelatos
2015-03-11 15:03                   ` Richard Cochran

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.