* [PATCH net-next 1/8] Documentation/bindings: net: ocelot: document the VCAP and PTP banks
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
@ 2019-01-17 10:02 ` Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 2/8] MIPS: dts: mscc: describe VCAP and PTP register ranges Antoine Tenart
` (8 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Antoine Tenart @ 2019-01-17 10:02 UTC (permalink / raw)
To: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton, jhogan
Cc: Antoine Tenart, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
Two additional register ranges needs to be described within the Ocelot
device tree node: the VCAP and the PTP ones. This patch documents the
binding needed to do so.
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
Documentation/devicetree/bindings/net/mscc-ocelot.txt | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/mscc-ocelot.txt b/Documentation/devicetree/bindings/net/mscc-ocelot.txt
index 9e5c17d426ce..08bc8d7f0c99 100644
--- a/Documentation/devicetree/bindings/net/mscc-ocelot.txt
+++ b/Documentation/devicetree/bindings/net/mscc-ocelot.txt
@@ -11,7 +11,9 @@ Required properties:
- reg-names: Must include the following entries:
- "sys"
- "rew"
+ - "vcap"
- "qs"
+ - "ptp"
- "qsys"
- "ana"
- "portX" with X from 0 to the number of last port index available on that
@@ -43,7 +45,9 @@ Example:
compatible = "mscc,vsc7514-switch";
reg = <0x1010000 0x10000>,
<0x1030000 0x10000>,
+ <0x1060000 0x10000>,
<0x1080000 0x100>,
+ <0x10e0000 0x10000>,
<0x11e0000 0x100>,
<0x11f0000 0x100>,
<0x1200000 0x100>,
@@ -57,9 +61,10 @@ Example:
<0x1280000 0x100>,
<0x1800000 0x80000>,
<0x1880000 0x10000>;
- reg-names = "sys", "rew", "qs", "port0", "port1", "port2",
- "port3", "port4", "port5", "port6", "port7",
- "port8", "port9", "port10", "qsys", "ana";
+ reg-names = "sys", "rew", "vcap", "qs", "ptp", "port0",
+ "port1", "port2", "port3", "port4", "port5",
+ "port6", "port7", "port8", "port9", "port10",
+ "qsys", "ana";
interrupts = <21 22>;
interrupt-names = "xtr", "inj";
--
2.20.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH net-next 2/8] MIPS: dts: mscc: describe VCAP and PTP register ranges
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 1/8] Documentation/bindings: net: ocelot: document the VCAP and PTP banks Antoine Tenart
@ 2019-01-17 10:02 ` Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 3/8] Documentation/bindings: net: ocelot: document the PTP ready IRQ Antoine Tenart
` (7 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Antoine Tenart @ 2019-01-17 10:02 UTC (permalink / raw)
To: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton, jhogan
Cc: Antoine Tenart, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
This patch adds two register ranges within the mscc,vsc7514-switch node,
to describe the VCAP and PTP registers.
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
arch/mips/boot/dts/mscc/ocelot.dtsi | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/arch/mips/boot/dts/mscc/ocelot.dtsi b/arch/mips/boot/dts/mscc/ocelot.dtsi
index 90c60d42f571..bb81652bebe8 100644
--- a/arch/mips/boot/dts/mscc/ocelot.dtsi
+++ b/arch/mips/boot/dts/mscc/ocelot.dtsi
@@ -119,7 +119,9 @@
compatible = "mscc,vsc7514-switch";
reg = <0x1010000 0x10000>,
<0x1030000 0x10000>,
+ <0x1060000 0x10000>,
<0x1080000 0x100>,
+ <0x10e0000 0x10000>,
<0x11e0000 0x100>,
<0x11f0000 0x100>,
<0x1200000 0x100>,
@@ -133,10 +135,10 @@
<0x1280000 0x100>,
<0x1800000 0x80000>,
<0x1880000 0x10000>;
- reg-names = "sys", "rew", "qs", "port0", "port1",
- "port2", "port3", "port4", "port5", "port6",
- "port7", "port8", "port9", "port10", "qsys",
- "ana";
+ reg-names = "sys", "rew", "vcap", "qs", "ptp", "port0",
+ "port1", "port2", "port3", "port4", "port5",
+ "port6", "port7", "port8", "port9",
+ "port10", "qsys", "ana";
interrupts = <21 22>;
interrupt-names = "xtr", "inj";
--
2.20.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH net-next 3/8] Documentation/bindings: net: ocelot: document the PTP ready IRQ
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 1/8] Documentation/bindings: net: ocelot: document the VCAP and PTP banks Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 2/8] MIPS: dts: mscc: describe VCAP and PTP register ranges Antoine Tenart
@ 2019-01-17 10:02 ` Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 4/8] MIPS: dts: mscc: describe the PTP ready interrupt Antoine Tenart
` (6 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Antoine Tenart @ 2019-01-17 10:02 UTC (permalink / raw)
To: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton, jhogan
Cc: Antoine Tenart, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
One additional interrupt needs to be described within the Ocelot device
tree node: the PTP ready one. This patch documents the binding needed to
do so.
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
Documentation/devicetree/bindings/net/mscc-ocelot.txt | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/mscc-ocelot.txt b/Documentation/devicetree/bindings/net/mscc-ocelot.txt
index 08bc8d7f0c99..aa33066f3403 100644
--- a/Documentation/devicetree/bindings/net/mscc-ocelot.txt
+++ b/Documentation/devicetree/bindings/net/mscc-ocelot.txt
@@ -18,9 +18,10 @@ Required properties:
- "ana"
- "portX" with X from 0 to the number of last port index available on that
switch
-- interrupts: Should contain the switch interrupts for frame extraction and
- frame injection
-- interrupt-names: should contain the interrupt names: "xtr", "inj"
+- interrupts: Should contain the switch interrupts for frame extraction,
+ frame injection and PTP ready.
+- interrupt-names: should contain the interrupt names: "xtr", "inj" and
+ "ptp_rdy".
- ethernet-ports: A container for child nodes representing switch ports.
The ethernet-ports container has the following properties
@@ -65,8 +66,8 @@ Example:
"port1", "port2", "port3", "port4", "port5",
"port6", "port7", "port8", "port9", "port10",
"qsys", "ana";
- interrupts = <21 22>;
- interrupt-names = "xtr", "inj";
+ interrupts = <18 21 22>;
+ interrupt-names = "ptp_rdy", "xtr", "inj";
ethernet-ports {
#address-cells = <1>;
--
2.20.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH net-next 4/8] MIPS: dts: mscc: describe the PTP ready interrupt
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
` (2 preceding siblings ...)
2019-01-17 10:02 ` [PATCH net-next 3/8] Documentation/bindings: net: ocelot: document the PTP ready IRQ Antoine Tenart
@ 2019-01-17 10:02 ` Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 5/8] net: mscc: describe the VCAP and PTP register ranges Antoine Tenart
` (5 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Antoine Tenart @ 2019-01-17 10:02 UTC (permalink / raw)
To: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton, jhogan
Cc: Antoine Tenart, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
This patch adds a description of the PTP ready interrupt, which can be
triggered when a PTP timestamp is available on an hardware FIFO.
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
arch/mips/boot/dts/mscc/ocelot.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/mips/boot/dts/mscc/ocelot.dtsi b/arch/mips/boot/dts/mscc/ocelot.dtsi
index bb81652bebe8..0bf5fa11c4e7 100644
--- a/arch/mips/boot/dts/mscc/ocelot.dtsi
+++ b/arch/mips/boot/dts/mscc/ocelot.dtsi
@@ -139,8 +139,8 @@
"port1", "port2", "port3", "port4", "port5",
"port6", "port7", "port8", "port9",
"port10", "qsys", "ana";
- interrupts = <21 22>;
- interrupt-names = "xtr", "inj";
+ interrupts = <18 21 22>;
+ interrupt-names = "ptp_rdy", "xtr", "inj";
ethernet-ports {
#address-cells = <1>;
--
2.20.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH net-next 5/8] net: mscc: describe the VCAP and PTP register ranges
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
` (3 preceding siblings ...)
2019-01-17 10:02 ` [PATCH net-next 4/8] MIPS: dts: mscc: describe the PTP ready interrupt Antoine Tenart
@ 2019-01-17 10:02 ` Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 6/8] net: mscc: improve the frame header parsing readability Antoine Tenart
` (4 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Antoine Tenart @ 2019-01-17 10:02 UTC (permalink / raw)
To: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton, jhogan
Cc: Antoine Tenart, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
This patch adds support for using the VCAP and PTP register ranges, and
adds a description of their registers. Those banks are used when
configuring PTP.
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
drivers/net/ethernet/mscc/ocelot.h | 18 ++++
drivers/net/ethernet/mscc/ocelot_board.c | 21 +++--
drivers/net/ethernet/mscc/ocelot_ptp.h | 41 +++++++++
drivers/net/ethernet/mscc/ocelot_regs.c | 22 +++++
drivers/net/ethernet/mscc/ocelot_vcap.h | 104 +++++++++++++++++++++++
5 files changed, 200 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/ethernet/mscc/ocelot_ptp.h
create mode 100644 drivers/net/ethernet/mscc/ocelot_vcap.h
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 086775f7b52f..4b1b180884ad 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -22,6 +22,8 @@
#include "ocelot_rew.h"
#include "ocelot_sys.h"
#include "ocelot_qs.h"
+#include "ocelot_ptp.h"
+#include "ocelot_vcap.h"
#define PGID_AGGR 64
#define PGID_SRC 80
@@ -69,6 +71,8 @@ enum ocelot_target {
REW,
SYS,
HSIO,
+ PTP,
+ VCAP,
TARGET_MAX,
};
@@ -334,6 +338,20 @@ enum ocelot_reg {
SYS_CM_DATA_RD,
SYS_CM_OP,
SYS_CM_DATA,
+ PTP_PIN_CFG = PTP << TARGET_OFFSET,
+ PTP_PIN_TOD_SEC_MSB,
+ PTP_PIN_TOD_SEC_LSB,
+ PTP_PIN_TOD_NSEC,
+ PTP_CFG_MISC,
+ PTP_CLK_CFG_ADJ_CFG,
+ PTP_CLK_CFG_ADJ_FREQ,
+ VCAP_UPDATE_CTRL = VCAP << TARGET_OFFSET,
+ VCAP_UPDATE_CTRL_MV_CFG,
+ VCAP_UPDATE_CTRL_ENTRY_DATA,
+ VCAP_UPDATE_CTRL_MASK_DATA,
+ VCAP_UPDATE_CTRL_ACTION_DATA,
+ VCAP_UPDATE_CTRL_COUNTER_DATA,
+ VCAP_CACHE_DATA_TYPE,
};
enum ocelot_regfield {
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index ca3ea2fbfcd0..ba7c93c4318a 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -182,12 +182,15 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
struct {
enum ocelot_target id;
char *name;
+ u8 optional:1;
} res[] = {
- { SYS, "sys" },
- { REW, "rew" },
- { QSYS, "qsys" },
- { ANA, "ana" },
- { QS, "qs" },
+ { SYS, "sys", 0 },
+ { REW, "rew", 0 },
+ { QSYS, "qsys", 0 },
+ { ANA, "ana", 0 },
+ { QS, "qs", 0 },
+ { PTP, "ptp", 1 },
+ { VCAP, "vcap", 1 },
};
if (!np && !pdev->dev.platform_data)
@@ -204,8 +207,14 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
struct regmap *target;
target = ocelot_io_platform_init(ocelot, pdev, res[i].name);
- if (IS_ERR(target))
+ if (IS_ERR(target)) {
+ if (res[i].optional) {
+ ocelot->targets[res[i].id] = NULL;
+ continue;
+ }
+
return PTR_ERR(target);
+ }
ocelot->targets[res[i].id] = target;
}
diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.h b/drivers/net/ethernet/mscc/ocelot_ptp.h
new file mode 100644
index 000000000000..9ede14a12573
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_ptp.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * License: Dual MIT/GPL
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_PTP_H_
+#define _MSCC_OCELOT_PTP_H_
+
+#define PTP_PIN_CFG_RSZ 0x20
+#define PTP_PIN_TOD_SEC_MSB_RSZ PTP_PIN_CFG_RSZ
+#define PTP_PIN_TOD_SEC_LSB_RSZ PTP_PIN_CFG_RSZ
+#define PTP_PIN_TOD_NSEC_RSZ PTP_PIN_CFG_RSZ
+
+#define PTP_PIN_CFG_DOM BIT(0)
+#define PTP_PIN_CFG_SYNC BIT(2)
+#define PTP_PIN_CFG_ACTION(x) ((x) << 3)
+#define PTP_PIN_CFG_ACTION_MASK PTP_PIN_CFG_ACTION(0x7)
+
+enum {
+ PTP_PIN_ACTION_IDLE = 0,
+ PTP_PIN_ACTION_LOAD,
+ PTP_PIN_ACTION_SAVE,
+ PTP_PIN_ACTION_CLOCK,
+ PTP_PIN_ACTION_DELTA,
+ PTP_PIN_ACTION_NOSYNC,
+ PTP_PIN_ACTION_SYNC,
+};
+
+#define PTP_CFG_MISC_PTP_EN BIT(2)
+
+#define PSEC_PER_SEC 1000000000000LL
+
+#define PTP_CFG_CLK_ADJ_CFG_ENA BIT(0)
+#define PTP_CFG_CLK_ADJ_CFG_DIR BIT(1)
+
+#define PTP_CFG_CLK_ADJ_FREQ_NS BIT(30)
+
+#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
index 9271af18b93b..bbba0f7a6962 100644
--- a/drivers/net/ethernet/mscc/ocelot_regs.c
+++ b/drivers/net/ethernet/mscc/ocelot_regs.c
@@ -224,12 +224,34 @@ static const u32 ocelot_sys_regmap[] = {
REG(SYS_PTP_CFG, 0x0006c4),
};
+static const u32 ocelot_ptp_regmap[] = {
+ REG(PTP_PIN_CFG, 0x000000),
+ REG(PTP_PIN_TOD_SEC_MSB, 0x000004),
+ REG(PTP_PIN_TOD_SEC_LSB, 0x000008),
+ REG(PTP_PIN_TOD_NSEC, 0x00000c),
+ REG(PTP_CFG_MISC, 0x0000a0),
+ REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4),
+ REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8),
+};
+
+static const u32 ocelot_vcap_regmap[] = {
+ REG(VCAP_UPDATE_CTRL, 0x000000),
+ REG(VCAP_UPDATE_CTRL_MV_CFG, 0x000004),
+ REG(VCAP_UPDATE_CTRL_ENTRY_DATA, 0x000008),
+ REG(VCAP_UPDATE_CTRL_MASK_DATA, 0x000108),
+ REG(VCAP_UPDATE_CTRL_ACTION_DATA, 0x000208),
+ REG(VCAP_UPDATE_CTRL_COUNTER_DATA, 0x000308),
+ REG(VCAP_CACHE_DATA_TYPE, 0x000388),
+};
+
static const u32 *ocelot_regmap[] = {
[ANA] = ocelot_ana_regmap,
[QS] = ocelot_qs_regmap,
[QSYS] = ocelot_qsys_regmap,
[REW] = ocelot_rew_regmap,
[SYS] = ocelot_sys_regmap,
+ [PTP] = ocelot_ptp_regmap,
+ [VCAP] = ocelot_vcap_regmap,
};
static const struct reg_field ocelot_regfields[] = {
diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.h b/drivers/net/ethernet/mscc/ocelot_vcap.h
new file mode 100644
index 000000000000..836bf0a96a73
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_vcap.h
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_VCAP_H_
+#define _MSCC_OCELOT_VCAP_H_
+
+/* Three PTP entries per port:
+ * - PTP ver Ethernet
+ * - PTP dst port 319
+ * - PTP dst port 320
+ */
+#define VCAP_IS2_N_PTP_ENTRIES 3
+
+/* VCAP */
+
+#define VCAP_UPDATE_CTRL_UPDATE_SHOT BIT(2)
+#define VCAP_UPDATE_CTRL_UPDATE_ADDR(x) (((x) & 0x3) << 16)
+#define VCAP_UPDATE_CTRL_UPDATE_COUNTER_DIS BIT(19)
+#define VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS BIT(20)
+#define VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS BIT(21)
+#define VCAP_UPDATE_CTRL_UPDATE_CMD(x) (((x) & 0x3) << 22)
+
+enum vcap_cmds {
+ VCAP_CMD_WRITE = 0,
+ VCAP_CMD_READ,
+ VCAP_CMD_MOVE_UP,
+ VCAP_CMD_MOVE_DOWN,
+ VCAP_CMD_INIT,
+};
+
+enum vcap_selector {
+ VCAP_SEL_COUNTER = BIT(0),
+ VCAP_SEL_ACTION = BIT(1),
+ VCAP_SEL_ENTRY = BIT(2),
+};
+
+struct vcap_data {
+ u32 entry[12];
+ u32 mask[12];
+ u32 action[4];
+ u32 counter;
+ u32 type_group;
+};
+
+/* VCAP IS2 lookup */
+
+#define VCAP_IS2_LKP_TYPE 0
+#define VCAP_IS2_LKP_INGRESS_PORT_MASK 13
+#define VCAP_IS2_LKP_MC 27
+#define VCAP_IS2_LKP_BC 28
+#define VCAP_IS2_LKP_VLAN 29
+#define VCAP_IS2_LKP_VID 30
+#define VCAP_IS2_LKP_IP4 46
+#define VCAP_IS2_LKP_DST_IP4 59
+#define VCAP_IS2_LKP_SRC_IP4 91
+#define VCAP_IS2_LKP_TCP 124
+#define VCAP_IS2_LKP_DPORT 125
+#define VCAP_IS2_LKP_SPORT 141
+#define VCAP_IS2_LKP_ETYPE 142
+
+/* Masks */
+#define VCAP_IS2_LKP_TYPE_M 0xf
+#define VCAP_IS2_LKP_INGRESS_PORT_MASK_M 0xfff
+#define VCAP_IS2_LKP_VID_M 0xfff
+#define VCAP_IS2_LKP_DST_IP4_M 0xffffffff
+#define VCAP_IS2_LKP_SRC_IP4_M 0xffffffff
+#define VCAP_IS2_LKP_DPORT_M 0xffff
+#define VCAP_IS2_LKP_SPORT_M 0xffff
+#define VCAP_IS2_LKP_ETYPE_M 0xffff
+
+/* IS2 lookup types */
+#define VCAP_IS2_LKP_TYPE_MAC_ETYPE 0
+#define VCAP_IS2_LKP_TYPE_TCP_UDP 4
+
+/* VCAP IS2 action */
+
+#define VCAP_IS2_ACT_MASK_MODE 5
+#define VCAP_IS2_ACT_PORT_MASK 20
+#define VCAP_IS2_ACT_REW_OP 31
+
+/* Masks */
+#define VCAP_IS2_ACT_PORT_MASK_M 0x7ff
+#define VCAP_IS2_ACT_REW_OP_M 0x1ff
+
+/* IS2 mask modes */
+#define VCAP_IS2_ACT_MASK_MODE_NOOP 0x0
+#define VCAP_IS2_ACT_MASK_MODE_FILTER 0x1
+
+/* IS2 REW OPS */
+#define VCAP_IS2_ACT_REW_OP_NOOP 0x0
+#define VCAP_IS2_ACT_REW_OP_PTP_ONE 0x2
+#define VCAP_IS2_ACT_REW_OP_PTP_TWO 0x3
+
+/* In addition to VCAP_IS2_REW_OP_PTP_ONE */
+#define VCAP_IS2_ACT_REW_OP_SUB_DELAY_1 (0x1 << 3)
+#define VCAP_IS2_ACT_REW_OP_SUB_DELAY_2 (0x2 << 3)
+#define VCAP_IS2_ACT_REW_OP_ADD_DELAY (0x1 << 5)
+#define VCAP_IS2_ACT_REW_OP_ADD_SUB (0x1 << 7)
+
+#endif
--
2.20.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH net-next 6/8] net: mscc: improve the frame header parsing readability
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
` (4 preceding siblings ...)
2019-01-17 10:02 ` [PATCH net-next 5/8] net: mscc: describe the VCAP and PTP register ranges Antoine Tenart
@ 2019-01-17 10:02 ` Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 7/8] net: mscc: remove the frame_info cpuq member Antoine Tenart
` (3 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Antoine Tenart @ 2019-01-17 10:02 UTC (permalink / raw)
To: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton, jhogan
Cc: Antoine Tenart, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
This cosmetic patch improves the frame header parsing readability by
introducing a new macro to access and mask its fields.
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
drivers/net/ethernet/mscc/ocelot_board.c | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index ba7c93c4318a..b85982e5717a 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -16,24 +16,26 @@
#include "ocelot.h"
-static int ocelot_parse_ifh(u32 *ifh, struct frame_info *info)
+#define IFH_EXTRACT_BITFIELD64(x, o, w) (((x) >> (o)) & GENMASK_ULL((w) - 1, 0))
+
+static int ocelot_parse_ifh(u32 *_ifh, struct frame_info *info)
{
- int i;
u8 llen, wlen;
+ u64 ifh[2];
+
+ ifh[0] = be64_to_cpu(((__force __be64 *)_ifh)[0]);
+ ifh[1] = be64_to_cpu(((__force __be64 *)_ifh)[1]);
- /* The IFH is in network order, switch to CPU order */
- for (i = 0; i < IFH_LEN; i++)
- ifh[i] = ntohl((__force __be32)ifh[i]);
+ wlen = IFH_EXTRACT_BITFIELD64(ifh[0], 7, 8);
+ llen = IFH_EXTRACT_BITFIELD64(ifh[0], 15, 6);
- wlen = (ifh[1] >> 7) & 0xff;
- llen = (ifh[1] >> 15) & 0x3f;
info->len = OCELOT_BUFFER_CELL_SZ * wlen + llen - 80;
- info->port = (ifh[2] & GENMASK(14, 11)) >> 11;
+ info->port = IFH_EXTRACT_BITFIELD64(ifh[1], 43, 4);
- info->cpuq = (ifh[3] & GENMASK(27, 20)) >> 20;
- info->tag_type = (ifh[3] & BIT(16)) >> 16;
- info->vid = ifh[3] & GENMASK(11, 0);
+ info->cpuq = IFH_EXTRACT_BITFIELD64(ifh[1], 20, 8);
+ info->tag_type = IFH_EXTRACT_BITFIELD64(ifh[1], 16, 1);
+ info->vid = IFH_EXTRACT_BITFIELD64(ifh[1], 0, 12);
return 0;
}
--
2.20.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH net-next 7/8] net: mscc: remove the frame_info cpuq member
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
` (5 preceding siblings ...)
2019-01-17 10:02 ` [PATCH net-next 6/8] net: mscc: improve the frame header parsing readability Antoine Tenart
@ 2019-01-17 10:02 ` Antoine Tenart
2019-01-17 10:02 ` [PATCH net-next 8/8] net: mscc: PTP offloading support Antoine Tenart
` (2 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Antoine Tenart @ 2019-01-17 10:02 UTC (permalink / raw)
To: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton, jhogan
Cc: Antoine Tenart, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
In struct frame_info, the cpuq member is never used. This cosmetic patch
removes it from the structure, and from the parsing of the frame header
as it's only set but never used.
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
drivers/net/ethernet/mscc/ocelot.h | 1 -
drivers/net/ethernet/mscc/ocelot_board.c | 1 -
2 files changed, 2 deletions(-)
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 4b1b180884ad..994ba953d60e 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -45,7 +45,6 @@ struct frame_info {
u32 len;
u16 port;
u16 vid;
- u8 cpuq;
u8 tag_type;
};
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index b85982e5717a..e0a3b6f70e8f 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -33,7 +33,6 @@ static int ocelot_parse_ifh(u32 *_ifh, struct frame_info *info)
info->port = IFH_EXTRACT_BITFIELD64(ifh[1], 43, 4);
- info->cpuq = IFH_EXTRACT_BITFIELD64(ifh[1], 20, 8);
info->tag_type = IFH_EXTRACT_BITFIELD64(ifh[1], 16, 1);
info->vid = IFH_EXTRACT_BITFIELD64(ifh[1], 0, 12);
--
2.20.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH net-next 8/8] net: mscc: PTP offloading support
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
` (6 preceding siblings ...)
2019-01-17 10:02 ` [PATCH net-next 7/8] net: mscc: remove the frame_info cpuq member Antoine Tenart
@ 2019-01-17 10:02 ` Antoine Tenart
2019-01-18 2:23 ` Richard Cochran
2019-01-18 2:13 ` [PATCH net-next 0/8] " Richard Cochran
2019-01-18 5:07 ` Florian Fainelli
9 siblings, 1 reply; 16+ messages in thread
From: Antoine Tenart @ 2019-01-17 10:02 UTC (permalink / raw)
To: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton, jhogan
Cc: Antoine Tenart, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
This patch adds support for offloading PTP timestamping to the Ocelot
switch for both 1-step and 2-step modes.
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
drivers/net/ethernet/mscc/ocelot.c | 509 ++++++++++++++++++++++-
drivers/net/ethernet/mscc/ocelot.h | 36 ++
drivers/net/ethernet/mscc/ocelot_board.c | 106 ++++-
3 files changed, 643 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 215a45374d7b..ed84c18adcfe 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
+#include <linux/ptp_clock_kernel.h>
#include <linux/skbuff.h>
#include <linux/iopoll.h>
#include <net/arp.h>
@@ -530,7 +531,7 @@ static int ocelot_port_stop(struct net_device *dev)
*/
static int ocelot_gen_ifh(u32 *ifh, struct frame_info *info)
{
- ifh[0] = IFH_INJ_BYPASS;
+ ifh[0] = IFH_INJ_BYPASS | ((0x1ff & info->rew_op) << 21);
ifh[1] = (0xf00 & info->port) >> 8;
ifh[2] = (0xff & info->port) << 24;
ifh[3] = (info->tag_type << 16) | info->vid;
@@ -542,6 +543,7 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ocelot_port *port = netdev_priv(dev);
struct ocelot *ocelot = port->ocelot;
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
u32 val, ifh[IFH_LEN];
struct frame_info info = {};
u8 grp = 0; /* Send everything on CPU group 0 */
@@ -558,6 +560,14 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
info.port = BIT(port->chip_port);
info.tag_type = IFH_TAG_TYPE_C;
info.vid = skb_vlan_tag_get(skb);
+
+ /* Check if timestamping is needed */
+ if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP) {
+ info.rew_op = port->ptp_cmd;
+ if (port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
+ info.rew_op |= (port->ts_id % 4) << 3;
+ }
+
ocelot_gen_ifh(ifh, &info);
for (i = 0; i < IFH_LEN; i++)
@@ -588,11 +598,44 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
- dev_kfree_skb_any(skb);
+
+ if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP &&
+ port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
+ struct ocelot_skb *oskb =
+ devm_kzalloc(ocelot->dev, sizeof(struct ocelot_skb),
+ GFP_KERNEL);
+
+ oskb->skb = skb;
+ oskb->id = port->ts_id % 4;
+ port->ts_id++;
+
+ list_add_tail(&oskb->head, &port->skbs);
+ } else {
+ dev_kfree_skb_any(skb);
+ }
return NETDEV_TX_OK;
}
+void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts)
+{
+ /* Read current PTP time to get seconds */
+ u32 val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
+
+ val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
+ val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE);
+ ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
+ ts->tv_sec = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
+
+ /* Read packet HW timestamp from FIFO */
+ val = ocelot_read(ocelot, SYS_PTP_TXSTAMP);
+ ts->tv_nsec = SYS_PTP_TXSTAMP_PTP_TXSTAMP(val);
+
+ /* Sec has incremented since the ts was registered */
+ if ((ts->tv_sec & 0x1) != !!(val & SYS_PTP_TXSTAMP_PTP_TXSTAMP_SEC))
+ ts->tv_sec--;
+}
+
static void ocelot_mact_mc_reset(struct ocelot_port *port)
{
struct ocelot *ocelot = port->ocelot;
@@ -915,6 +958,262 @@ static int ocelot_set_features(struct net_device *dev,
return 0;
}
+static void ocelot_vcap_is2_cmd(struct ocelot *ocelot, u8 addr,
+ enum vcap_cmds cmd, enum vcap_selector sel)
+{
+ u32 val = VCAP_UPDATE_CTRL_UPDATE_CMD(cmd) |
+ VCAP_UPDATE_CTRL_UPDATE_ADDR(addr) |
+ VCAP_UPDATE_CTRL_UPDATE_SHOT;
+
+ /* Select the destination/origin */
+ if (!(sel & VCAP_SEL_COUNTER))
+ val |= VCAP_UPDATE_CTRL_UPDATE_COUNTER_DIS;
+ if (!(sel & VCAP_SEL_ACTION))
+ val |= VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS;
+ if (!(sel & VCAP_SEL_ENTRY))
+ val |= VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS;
+
+ ocelot_write(ocelot, val, VCAP_UPDATE_CTRL);
+
+ /* wait for the command to complete */
+ do {
+ val = ocelot_read(ocelot, VCAP_UPDATE_CTRL);
+ } while (val & VCAP_UPDATE_CTRL_UPDATE_SHOT);
+}
+
+static void ocelot_vcap_entry_to_cache(struct ocelot *ocelot,
+ struct vcap_data *data)
+{
+ int i;
+
+ for (i = 0; i < 12; i++) {
+ ocelot_write(ocelot, data->entry[i],
+ VCAP_UPDATE_CTRL_ENTRY_DATA + i * sizeof(u32));
+ ocelot_write(ocelot, ~data->mask[i],
+ VCAP_UPDATE_CTRL_MASK_DATA + i * sizeof(u32));
+ }
+
+ ocelot_write(ocelot, data->type_group, VCAP_CACHE_DATA_TYPE);
+}
+
+static void ocelot_vcap_action_to_cache(struct ocelot *ocelot,
+ struct vcap_data *data)
+{
+ int i;
+
+ /* Encode the type */
+ data->action[0] &= ~BIT(0);
+
+ for (i = 0; i < 4; i++)
+ ocelot_write(ocelot, data->action[i],
+ VCAP_UPDATE_CTRL_ACTION_DATA + i * sizeof(u32));
+
+ ocelot_write(ocelot, data->counter, VCAP_UPDATE_CTRL_COUNTER_DATA);
+}
+
+static void ocelot_vcap_is2_init(struct ocelot *ocelot)
+{
+ struct vcap_data data;
+ int port;
+
+ mutex_init(&ocelot->ptp_lock);
+
+ memset(&data, 0, sizeof(data));
+
+ /* Initialize entries */
+ ocelot_vcap_entry_to_cache(ocelot, &data);
+ ocelot_write(ocelot, 64 /* entry count */, VCAP_UPDATE_CTRL_MV_CFG);
+ ocelot_vcap_is2_cmd(ocelot, 0, VCAP_CMD_INIT, VCAP_SEL_ENTRY);
+
+ /* Initialize actions */
+ ocelot_vcap_action_to_cache(ocelot, &data);
+ ocelot_write(ocelot, 64 + ocelot->num_phys_ports + 2 /* action count */,
+ VCAP_UPDATE_CTRL_MV_CFG);
+ ocelot_vcap_is2_cmd(ocelot, 0, VCAP_CMD_INIT,
+ VCAP_SEL_ACTION | VCAP_SEL_COUNTER);
+
+ /* Enable the IS2 engine */
+ for (port = 0; port < ocelot->num_phys_ports; port++) {
+ ocelot_write_gix(ocelot, ANA_PORT_VCAP_S2_CFG_S2_ENA |
+ ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(0xa),
+ ANA_PORT_VCAP_S2_CFG, port);
+ ocelot_write_gix(ocelot, 0, ANA_PORT_PTP_CFG, port);
+ }
+}
+
+static void ocelot_vcap_is2_set(struct ocelot *ocelot, u8 addr,
+ struct vcap_data *data)
+{
+ ocelot_vcap_entry_to_cache(ocelot, data);
+ ocelot_vcap_action_to_cache(ocelot, data);
+ ocelot_vcap_is2_cmd(ocelot, addr, VCAP_CMD_WRITE,
+ VCAP_SEL_ENTRY | VCAP_SEL_ACTION | VCAP_SEL_COUNTER);
+}
+
+static inline void ocelot_set_bits(u32 *data, u32 offset, u32 mask, u32 val)
+{
+ u32 word_off = offset / 32, bit_off = offset % 32;
+
+ data[word_off] &= ~(mask << bit_off);
+ data[word_off] |= val << bit_off;
+ if (get_bitmask_order(mask) > (32 - bit_off)) {
+ data[word_off + 1] &= ~(mask >> (32 - bit_off));
+ data[word_off + 1] |= val >> (32 - bit_off);
+ }
+}
+
+static void ocelot_vcap_is2_set_lookup(struct vcap_data *data, u32 offset,
+ u32 mask, u32 val)
+{
+ ocelot_set_bits(data->entry, offset, mask, val);
+ ocelot_set_bits(data->mask, offset, mask, mask);
+}
+
+static void ocelot_vcap_is2_set_action(struct vcap_data *data, u32 offset,
+ u32 mask, u32 val)
+{
+ ocelot_set_bits(data->action, offset, mask, val);
+}
+
+static int ocelot_hwstamp_get(struct ocelot_port *port, struct ifreq *ifr)
+{
+ struct ocelot *ocelot = port->ocelot;
+
+ return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config,
+ sizeof(ocelot->hwtstamp_config)) ? -EFAULT : 0;
+}
+
+static int ocelot_hwstamp_set(struct ocelot_port *port, struct ifreq *ifr)
+{
+ struct ocelot *ocelot = port->ocelot;
+ struct hwtstamp_config cfg;
+ struct vcap_data data;
+ int base = port->chip_port * VCAP_IS2_N_PTP_ENTRIES;
+ u32 ptp_op = VCAP_IS2_ACT_REW_OP_PTP_ONE;
+
+ if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+ return -EFAULT;
+
+ /* reserved for future extensions */
+ if (cfg.flags)
+ return -EINVAL;
+
+ /* Tx type sanity check */
+ switch (cfg.tx_type) {
+ case HWTSTAMP_TX_ON:
+ port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
+ break;
+ case HWTSTAMP_TX_ONESTEP_SYNC:
+ /* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we
+ * need to update the origin time.
+ */
+ port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP;
+ break;
+ case HWTSTAMP_TX_OFF:
+ port->ptp_cmd = 0;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ mutex_lock(&ocelot->ptp_lock);
+
+ /* Prepare the VCAP PTP entry */
+ memset(&data, 0, sizeof(data));
+
+ switch (cfg.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ ptp_op = VCAP_IS2_ACT_REW_OP_NOOP;
+ break;
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_NTP_ALL:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ break;
+ default:
+ mutex_unlock(&ocelot->ptp_lock);
+ return -ERANGE;
+ }
+
+ /* Set the PTP action */
+ ocelot_vcap_is2_set_action(&data, VCAP_IS2_ACT_REW_OP,
+ VCAP_IS2_ACT_REW_OP_M, ptp_op);
+
+ data.type_group = 2;
+
+ /* Port mask */
+ ocelot_vcap_is2_set_lookup(&data, VCAP_IS2_LKP_INGRESS_PORT_MASK,
+ VCAP_IS2_LKP_INGRESS_PORT_MASK_M, 0x7ff);
+
+ /* Commit the PTP VCAP entries:
+ *
+ * - One entry for PTP over Ethernet (etype 0x88f7).
+ * - One entry for PTP over IPv4/v6 UDP dst port 319.
+ * - One entry for PTP over IPv4/v6 UDP dst port 320.
+ */
+
+ /* PTP over Ethernet */
+ ocelot_vcap_is2_set_lookup(&data, VCAP_IS2_LKP_TYPE,
+ VCAP_IS2_LKP_TYPE_M,
+ VCAP_IS2_LKP_TYPE_MAC_ETYPE);
+ ocelot_vcap_is2_set_lookup(&data, VCAP_IS2_LKP_ETYPE,
+ VCAP_IS2_LKP_ETYPE_M, 0x88f7);
+ ocelot_vcap_is2_set(ocelot, base++, &data);
+
+ /* PTP over IPv4/v6 UDP dst port 319 */
+ ocelot_vcap_is2_set_lookup(&data, VCAP_IS2_LKP_TYPE,
+ VCAP_IS2_LKP_TYPE_M,
+ VCAP_IS2_LKP_TYPE_TCP_UDP);
+ ocelot_vcap_is2_set_lookup(&data, VCAP_IS2_LKP_DPORT,
+ VCAP_IS2_LKP_DPORT_M, 319);
+ ocelot_vcap_is2_set(ocelot, base++, &data);
+
+ /* PTP over IPv4/v6 UDP dst port 320 */
+ ocelot_vcap_is2_set_lookup(&data, VCAP_IS2_LKP_TYPE,
+ VCAP_IS2_LKP_TYPE_M,
+ VCAP_IS2_LKP_TYPE_TCP_UDP);
+ ocelot_vcap_is2_set_lookup(&data, VCAP_IS2_LKP_DPORT,
+ VCAP_IS2_LKP_DPORT_M, 320);
+ ocelot_vcap_is2_set(ocelot, base++, &data);
+
+ /* Commit back the result & save it */
+ memcpy(&ocelot->hwtstamp_config, &cfg, sizeof(cfg));
+ mutex_unlock(&ocelot->ptp_lock);
+
+ return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+
+static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ocelot_port *port = netdev_priv(dev);
+ struct ocelot *ocelot = port->ocelot;
+
+ /* The function is only used for PTP operations for now */
+ if (!ocelot->ptp)
+ return -EOPNOTSUPP;
+
+ switch (cmd) {
+ case SIOCSHWTSTAMP:
+ return ocelot_hwstamp_set(port, ifr);
+ case SIOCGHWTSTAMP:
+ return ocelot_hwstamp_get(port, ifr);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct net_device_ops ocelot_port_netdev_ops = {
.ndo_open = ocelot_port_open,
.ndo_stop = ocelot_port_stop,
@@ -929,6 +1228,7 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
.ndo_vlan_rx_add_vid = ocelot_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
.ndo_set_features = ocelot_set_features,
+ .ndo_do_ioctl = ocelot_ioctl,
};
static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
@@ -1004,12 +1304,42 @@ static int ocelot_get_sset_count(struct net_device *dev, int sset)
return ocelot->num_stats;
}
+static int ocelot_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+ struct ocelot_port *ocelot_port = netdev_priv(dev);
+ struct ocelot *ocelot = ocelot_port->ocelot;
+ int ret;
+
+ if (!ocelot->ptp)
+ return -EOPNOTSUPP;
+
+ ret = ethtool_op_get_ts_info(dev, info);
+ if (ret)
+ return ret;
+
+ info->phc_index = ocelot->ptp_clock ?
+ ptp_clock_index(ocelot->ptp_clock) : -1;
+ info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) |
+ BIT(HWTSTAMP_TX_ONESTEP_SYNC);
+ info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
+
+ return 0;
+}
+
static const struct ethtool_ops ocelot_ethtool_ops = {
.get_strings = ocelot_get_strings,
.get_ethtool_stats = ocelot_get_ethtool_stats,
.get_sset_count = ocelot_get_sset_count,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_ts_info = ocelot_get_ts_info,
};
static int ocelot_port_attr_get(struct net_device *dev,
@@ -1616,6 +1946,165 @@ struct notifier_block ocelot_switchdev_blocking_nb __read_mostly = {
};
EXPORT_SYMBOL(ocelot_switchdev_blocking_nb);
+int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
+{
+ struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
+ u32 val;
+ time64_t s;
+ s64 ns;
+
+ val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
+ val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
+ val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE);
+ ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
+
+ s = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN);
+ s += ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
+ ns = ocelot_read_rix(ocelot, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
+
+ /* Deal with negative values */
+ if (ns >= 0x3ffffff0 && ns <= 0x3fffffff) {
+ s--;
+ ns &= 0xf;
+ ns += 999999984;
+ }
+
+ set_normalized_timespec64(ts, s, ns);
+ return 0;
+}
+
+static int ocelot_ptp_settime64(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
+ u32 val;
+
+ val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
+ val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
+ val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
+
+ ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
+
+ ocelot_write_rix(ocelot, lower_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_LSB,
+ TOD_ACC_PIN);
+ ocelot_write_rix(ocelot, upper_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_MSB,
+ TOD_ACC_PIN);
+ ocelot_write_rix(ocelot, ts->tv_nsec, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
+
+ val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
+ val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
+ val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_LOAD);
+
+ ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
+
+ return 0;
+}
+
+static int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) {
+ struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
+ u32 val;
+
+ val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
+ val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
+ val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
+
+ ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
+
+ ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
+ ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN);
+ ocelot_write_rix(ocelot, delta, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
+
+ val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
+ val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
+ val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_DELTA);
+
+ ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
+ } else {
+ /* Fall back using ocelot_ptp_settime64 which is not exact. */
+ struct timespec64 ts;
+ u64 now;
+
+ ocelot_ptp_gettime64(ptp, &ts);
+
+ now = ktime_to_ns(timespec64_to_ktime(ts));
+ ts = ns_to_timespec64(now + delta);
+
+ ocelot_ptp_settime64(ptp, &ts);
+ }
+ return 0;
+}
+
+static int ocelot_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
+ u64 adj = 0;
+ u32 unit = 0, direction = 0;
+
+ if (!ppb)
+ goto disable_adj;
+
+ if (ppb < 0) {
+ direction = PTP_CFG_CLK_ADJ_CFG_DIR;
+ ppb = -ppb;
+ }
+
+ adj = PSEC_PER_SEC;
+ do_div(adj, ppb);
+
+ /* If the adjustment value is too large, use ns instead */
+ if (adj >= (1L << 30)) {
+ unit = PTP_CFG_CLK_ADJ_FREQ_NS;
+ do_div(adj, 1000);
+ }
+
+ /* Still too big */
+ if (adj >= (1L << 30))
+ goto disable_adj;
+
+ ocelot_write(ocelot, unit | adj, PTP_CLK_CFG_ADJ_FREQ);
+ ocelot_write(ocelot, PTP_CFG_CLK_ADJ_CFG_ENA | direction,
+ PTP_CLK_CFG_ADJ_CFG);
+ return 0;
+
+disable_adj:
+ ocelot_write(ocelot, 0, PTP_CLK_CFG_ADJ_CFG);
+ return 0;
+}
+
+static struct ptp_clock_info ocelot_ptp_clock_info = {
+ .owner = THIS_MODULE,
+ .name = "ocelot ptp",
+ .max_adj = 0x7fffffff,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .n_pins = 0,
+ .pps = 0,
+ .gettime64 = ocelot_ptp_gettime64,
+ .settime64 = ocelot_ptp_settime64,
+ .adjtime = ocelot_ptp_adjtime,
+ .adjfreq = ocelot_ptp_adjfreq,
+};
+
+static int ocelot_init_timestamp(struct ocelot *ocelot)
+{
+ ocelot->ptp_info = ocelot_ptp_clock_info;
+
+ ocelot->ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev);
+ if (IS_ERR(ocelot->ptp_clock))
+ return PTR_ERR(ocelot->ptp_clock);
+
+ ocelot_write(ocelot, SYS_PTP_CFG_PTP_STAMP_WID(30), SYS_PTP_CFG);
+ ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_LOW);
+ ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_HIGH);
+
+ ocelot_write(ocelot, PTP_CFG_MISC_PTP_EN, PTP_CFG_MISC);
+
+ return 0;
+}
+
int ocelot_probe_port(struct ocelot *ocelot, u8 port,
void __iomem *regs,
struct phy_device *phy)
@@ -1649,6 +2138,8 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, ocelot_port->pvid,
ENTRYTYPE_LOCKED);
+ INIT_LIST_HEAD(&ocelot_port->skbs);
+
err = register_netdev(dev);
if (err) {
dev_err(ocelot->dev, "register_netdev failed\n");
@@ -1669,7 +2160,7 @@ EXPORT_SYMBOL(ocelot_probe_port);
int ocelot_init(struct ocelot *ocelot)
{
u32 port;
- int i, cpu = ocelot->num_phys_ports;
+ int i, ret, cpu = ocelot->num_phys_ports;
char queue_name[32];
ocelot->lags = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
@@ -1796,6 +2287,18 @@ int ocelot_init(struct ocelot *ocelot)
INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats);
queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
OCELOT_STATS_CHECK_DELAY);
+
+ if (ocelot->ptp) {
+ ret = ocelot_init_timestamp(ocelot);
+ if (ret) {
+ dev_err(ocelot->dev,
+ "Timestamp initialization failed\n");
+ return ret;
+ }
+
+ ocelot_vcap_is2_init(ocelot);
+ }
+
return 0;
}
EXPORT_SYMBOL(ocelot_init);
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 994ba953d60e..ed1583037dc2 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -11,9 +11,11 @@
#include <linux/bitops.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
+#include <linux/net_tstamp.h>
#include <linux/phy.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/ptp_clock_kernel.h>
#include <linux/regmap.h>
#include "ocelot_ana.h"
@@ -46,6 +48,8 @@ struct frame_info {
u16 port;
u16 vid;
u8 tag_type;
+ u16 rew_op;
+ u32 timestamp; /* rew_val */
};
#define IFH_INJ_BYPASS BIT(31)
@@ -54,6 +58,12 @@ struct frame_info {
#define IFH_TAG_TYPE_C 0
#define IFH_TAG_TYPE_S 1
+#define IFH_REW_OP_NOOP 0x0
+#define IFH_REW_OP_DSCP 0x1
+#define IFH_REW_OP_ONE_STEP_PTP 0x2
+#define IFH_REW_OP_TWO_STEP_PTP 0x3
+#define IFH_REW_OP_ORIGIN_PTP 0x5
+
#define OCELOT_SPEED_2500 0
#define OCELOT_SPEED_1000 1
#define OCELOT_SPEED_100 2
@@ -401,6 +411,13 @@ enum ocelot_regfield {
REGFIELD_MAX
};
+enum ocelot_clk_pins {
+ ALT_PPS_PIN = 1,
+ EXT_CLK_PIN,
+ ALT_LDST_PIN,
+ TOD_ACC_PIN
+};
+
struct ocelot_multicast {
struct list_head list;
unsigned char addr[ETH_ALEN];
@@ -450,6 +467,12 @@ struct ocelot {
u64 *stats;
struct delayed_work stats_work;
struct workqueue_struct *stats_queue;
+
+ u8 ptp:1;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_info;
+ struct hwtstamp_config hwtstamp_config;
+ struct mutex ptp_lock;
};
struct ocelot_port {
@@ -475,6 +498,16 @@ struct ocelot_port {
phy_interface_t phy_mode;
struct phy *serdes;
+
+ u8 ptp_cmd;
+ struct list_head skbs;
+ u8 ts_id;
+};
+
+struct ocelot_skb {
+ struct list_head head;
+ struct sk_buff *skb;
+ u8 id;
};
u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
@@ -518,4 +551,7 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
extern struct notifier_block ocelot_netdevice_nb;
extern struct notifier_block ocelot_switchdev_blocking_nb;
+int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
+void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts);
+
#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index e0a3b6f70e8f..d85920c05269 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -31,6 +31,8 @@ static int ocelot_parse_ifh(u32 *_ifh, struct frame_info *info)
info->len = OCELOT_BUFFER_CELL_SZ * wlen + llen - 80;
+ info->timestamp = IFH_EXTRACT_BITFIELD64(ifh[0], 21, 32);
+
info->port = IFH_EXTRACT_BITFIELD64(ifh[1], 43, 4);
info->tag_type = IFH_EXTRACT_BITFIELD64(ifh[1], 16, 1);
@@ -98,7 +100,11 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
int sz, len, buf_len;
u32 ifh[4];
u32 val;
- struct frame_info info;
+ struct frame_info info = {};
+ struct timespec64 ts;
+ struct skb_shared_hwtstamps *shhwtstamps;
+ u64 tod_in_ns;
+ u64 full_ts_in_ns;
for (i = 0; i < IFH_LEN; i++) {
err = ocelot_rx_frame_word(ocelot, grp, true, &ifh[i]);
@@ -145,6 +151,22 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
break;
}
+ if (ocelot->ptp) {
+ ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
+
+ tod_in_ns = ktime_set(ts.tv_sec, ts.tv_nsec);
+ if ((tod_in_ns & 0xffffffff) < info.timestamp)
+ full_ts_in_ns = (((tod_in_ns >> 32) - 1) << 32) |
+ info.timestamp;
+ else
+ full_ts_in_ns = (tod_in_ns & GENMASK_ULL(63, 32)) |
+ info.timestamp;
+
+ shhwtstamps = skb_hwtstamps(skb);
+ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamps->hwtstamp = full_ts_in_ns;
+ }
+
/* Everything we see on an interface that is in the HW bridge
* has already been forwarded.
*/
@@ -164,6 +186,65 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
+static irqreturn_t ocelot_ptp_rdy_irq_handler(int irq, void *arg)
+{
+ struct ocelot *ocelot = arg;
+
+ do {
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct list_head *pos, *tmp;
+ struct ocelot_skb *entry;
+ struct ocelot_port *port;
+ struct timespec64 ts;
+ struct sk_buff *skb = NULL;
+ u32 val, id, txport;
+
+ val = ocelot_read(ocelot, SYS_PTP_STATUS);
+
+ /* Check if a timestamp can be retrieved */
+ if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD))
+ break;
+
+ WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL);
+
+ /* Retrieve the ts ID and Tx port */
+ id = SYS_PTP_STATUS_PTP_MESS_ID_X(val);
+ txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val);
+
+ /* Retrieve its associated skb */
+ port = ocelot->ports[txport];
+
+ list_for_each_safe(pos, tmp, &port->skbs) {
+ entry = list_entry(pos, struct ocelot_skb, head);
+ if (entry->id != id)
+ continue;
+
+ skb = entry->skb;
+
+ list_del(pos);
+ devm_kfree(ocelot->dev, entry);
+ }
+
+ /* Next ts */
+ ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT);
+
+ if (unlikely(!skb))
+ continue;
+
+ /* Get the h/w timestamp */
+ ocelot_get_hwtimestamp(ocelot, &ts);
+
+ /* Set the timestamp into the skb */
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+ skb_tstamp_tx(skb, &shhwtstamps);
+
+ dev_kfree_skb_any(skb);
+ } while (true);
+
+ return IRQ_HANDLED;
+}
+
static const struct of_device_id mscc_ocelot_match[] = {
{ .compatible = "mscc,vsc7514-switch" },
{ }
@@ -172,8 +253,8 @@ MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
static int mscc_ocelot_probe(struct platform_device *pdev)
{
- int err, irq;
unsigned int i;
+ int err, irq_xtr, irq_ptp_rdy;
struct device_node *np = pdev->dev.of_node;
struct device_node *ports, *portnp;
struct ocelot *ocelot;
@@ -232,16 +313,31 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
if (err)
return err;
- irq = platform_get_irq_byname(pdev, "xtr");
- if (irq < 0)
+ irq_xtr = platform_get_irq_byname(pdev, "xtr");
+ if (irq_xtr < 0)
return -ENODEV;
- err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ err = devm_request_threaded_irq(&pdev->dev, irq_xtr, NULL,
ocelot_xtr_irq_handler, IRQF_ONESHOT,
"frame extraction", ocelot);
if (err)
return err;
+
+ irq_ptp_rdy = platform_get_irq_byname(pdev, "ptp_rdy");
+ if (irq_ptp_rdy > 0) {
+ err = devm_request_threaded_irq(&pdev->dev, irq_ptp_rdy, NULL,
+ ocelot_ptp_rdy_irq_handler,
+ IRQF_ONESHOT, "ptp ready",
+ ocelot);
+ if (err)
+ return err;
+ }
+
+ /* Check if we can support PTP */
+ if (irq_ptp_rdy > 0 && ocelot->targets[PTP] && ocelot->targets[VCAP])
+ ocelot->ptp = 1;
+
regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1);
regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
--
2.20.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH net-next 8/8] net: mscc: PTP offloading support
2019-01-17 10:02 ` [PATCH net-next 8/8] net: mscc: PTP offloading support Antoine Tenart
@ 2019-01-18 2:23 ` Richard Cochran
2019-01-18 9:08 ` Antoine Tenart
0 siblings, 1 reply; 16+ messages in thread
From: Richard Cochran @ 2019-01-18 2:23 UTC (permalink / raw)
To: Antoine Tenart
Cc: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton,
jhogan, netdev, linux-mips, thomas.petazzoni, quentin.schulz,
allan.nielsen
On Thu, Jan 17, 2019 at 11:02:12AM +0100, Antoine Tenart wrote:
> This patch adds support for offloading PTP timestamping to the Ocelot
> switch for both 1-step and 2-step modes.
For PTP Hardware Clock drivers, please add the PTP maintainer onto CC.
> +int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
> +{
> + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
> + u32 val;
> + time64_t s;
> + s64 ns;
> +
> + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
> + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
> + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE);
> + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
> +
> + s = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN);
> + s += ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
> + ns = ocelot_read_rix(ocelot, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
> +
> + /* Deal with negative values */
> + if (ns >= 0x3ffffff0 && ns <= 0x3fffffff) {
> + s--;
> + ns &= 0xf;
> + ns += 999999984;
> + }
> +
> + set_normalized_timespec64(ts, s, ns);
> + return 0;
> +}
> +
> +static int ocelot_ptp_settime64(struct ptp_clock_info *ptp,
> + const struct timespec64 *ts)
> +{
> + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
> + u32 val;
> +
> + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
> + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
> + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
> +
> + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
> +
> + ocelot_write_rix(ocelot, lower_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_LSB,
> + TOD_ACC_PIN);
> + ocelot_write_rix(ocelot, upper_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_MSB,
> + TOD_ACC_PIN);
> + ocelot_write_rix(ocelot, ts->tv_nsec, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
> +
> + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
> + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
> + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_LOAD);
> +
> + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
You are writing multiple registers. This code is not safe when called
concurrently.
Ditto for gettime, adjtime, and adjfreq.
> + return 0;
> +}
> +
> +static int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
> +{
> + if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) {
> + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
> + u32 val;
> +
> + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
> + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
> + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
> +
> + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
> +
> + ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
> + ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN);
> + ocelot_write_rix(ocelot, delta, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
> +
> + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
> + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
> + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_DELTA);
> +
> + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
> + } else {
> + /* Fall back using ocelot_ptp_settime64 which is not exact. */
> + struct timespec64 ts;
> + u64 now;
> +
> + ocelot_ptp_gettime64(ptp, &ts);
> +
> + now = ktime_to_ns(timespec64_to_ktime(ts));
> + ts = ns_to_timespec64(now + delta);
> +
> + ocelot_ptp_settime64(ptp, &ts);
> + }
> + return 0;
> +}
> +
> +static int ocelot_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
> +{
Please implement adjfine instead.
> + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
> + u64 adj = 0;
> + u32 unit = 0, direction = 0;
> +
> + if (!ppb)
> + goto disable_adj;
> +
> + if (ppb < 0) {
> + direction = PTP_CFG_CLK_ADJ_CFG_DIR;
> + ppb = -ppb;
> + }
> +
> + adj = PSEC_PER_SEC;
> + do_div(adj, ppb);
> +
> + /* If the adjustment value is too large, use ns instead */
> + if (adj >= (1L << 30)) {
> + unit = PTP_CFG_CLK_ADJ_FREQ_NS;
> + do_div(adj, 1000);
> + }
> +
> + /* Still too big */
> + if (adj >= (1L << 30))
> + goto disable_adj;
> +
> + ocelot_write(ocelot, unit | adj, PTP_CLK_CFG_ADJ_FREQ);
> + ocelot_write(ocelot, PTP_CFG_CLK_ADJ_CFG_ENA | direction,
> + PTP_CLK_CFG_ADJ_CFG);
> + return 0;
> +
> +disable_adj:
> + ocelot_write(ocelot, 0, PTP_CLK_CFG_ADJ_CFG);
> + return 0;
> +}
> +
> +static struct ptp_clock_info ocelot_ptp_clock_info = {
> + .owner = THIS_MODULE,
> + .name = "ocelot ptp",
> + .max_adj = 0x7fffffff,
> + .n_alarm = 0,
> + .n_ext_ts = 0,
> + .n_per_out = 0,
> + .n_pins = 0,
> + .pps = 0,
> + .gettime64 = ocelot_ptp_gettime64,
> + .settime64 = ocelot_ptp_settime64,
> + .adjtime = ocelot_ptp_adjtime,
> + .adjfreq = ocelot_ptp_adjfreq,
> +};
> +
> +static int ocelot_init_timestamp(struct ocelot *ocelot)
> +{
> + ocelot->ptp_info = ocelot_ptp_clock_info;
> +
> + ocelot->ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev);
> + if (IS_ERR(ocelot->ptp_clock))
> + return PTR_ERR(ocelot->ptp_clock);
> +
> + ocelot_write(ocelot, SYS_PTP_CFG_PTP_STAMP_WID(30), SYS_PTP_CFG);
> + ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_LOW);
> + ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_HIGH);
> +
> + ocelot_write(ocelot, PTP_CFG_MISC_PTP_EN, PTP_CFG_MISC);
> +
> + return 0;
> +}
> +
> int ocelot_probe_port(struct ocelot *ocelot, u8 port,
> void __iomem *regs,
> struct phy_device *phy)
> @@ -1649,6 +2138,8 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
> ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, ocelot_port->pvid,
> ENTRYTYPE_LOCKED);
>
> + INIT_LIST_HEAD(&ocelot_port->skbs);
> +
> err = register_netdev(dev);
> if (err) {
> dev_err(ocelot->dev, "register_netdev failed\n");
> @@ -1669,7 +2160,7 @@ EXPORT_SYMBOL(ocelot_probe_port);
> int ocelot_init(struct ocelot *ocelot)
> {
> u32 port;
> - int i, cpu = ocelot->num_phys_ports;
> + int i, ret, cpu = ocelot->num_phys_ports;
> char queue_name[32];
>
> ocelot->lags = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
> @@ -1796,6 +2287,18 @@ int ocelot_init(struct ocelot *ocelot)
> INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats);
> queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
> OCELOT_STATS_CHECK_DELAY);
> +
> + if (ocelot->ptp) {
> + ret = ocelot_init_timestamp(ocelot);
> + if (ret) {
> + dev_err(ocelot->dev,
> + "Timestamp initialization failed\n");
> + return ret;
> + }
> +
> + ocelot_vcap_is2_init(ocelot);
> + }
> +
> return 0;
> }
> EXPORT_SYMBOL(ocelot_init);
> diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
> index 994ba953d60e..ed1583037dc2 100644
> --- a/drivers/net/ethernet/mscc/ocelot.h
> +++ b/drivers/net/ethernet/mscc/ocelot.h
> @@ -11,9 +11,11 @@
> #include <linux/bitops.h>
> #include <linux/etherdevice.h>
> #include <linux/if_vlan.h>
> +#include <linux/net_tstamp.h>
> #include <linux/phy.h>
> #include <linux/phy/phy.h>
> #include <linux/platform_device.h>
> +#include <linux/ptp_clock_kernel.h>
> #include <linux/regmap.h>
>
> #include "ocelot_ana.h"
> @@ -46,6 +48,8 @@ struct frame_info {
> u16 port;
> u16 vid;
> u8 tag_type;
> + u16 rew_op;
> + u32 timestamp; /* rew_val */
> };
>
> #define IFH_INJ_BYPASS BIT(31)
> @@ -54,6 +58,12 @@ struct frame_info {
> #define IFH_TAG_TYPE_C 0
> #define IFH_TAG_TYPE_S 1
>
> +#define IFH_REW_OP_NOOP 0x0
> +#define IFH_REW_OP_DSCP 0x1
> +#define IFH_REW_OP_ONE_STEP_PTP 0x2
> +#define IFH_REW_OP_TWO_STEP_PTP 0x3
> +#define IFH_REW_OP_ORIGIN_PTP 0x5
> +
> #define OCELOT_SPEED_2500 0
> #define OCELOT_SPEED_1000 1
> #define OCELOT_SPEED_100 2
> @@ -401,6 +411,13 @@ enum ocelot_regfield {
> REGFIELD_MAX
> };
>
> +enum ocelot_clk_pins {
> + ALT_PPS_PIN = 1,
> + EXT_CLK_PIN,
> + ALT_LDST_PIN,
> + TOD_ACC_PIN
> +};
> +
> struct ocelot_multicast {
> struct list_head list;
> unsigned char addr[ETH_ALEN];
> @@ -450,6 +467,12 @@ struct ocelot {
> u64 *stats;
> struct delayed_work stats_work;
> struct workqueue_struct *stats_queue;
> +
> + u8 ptp:1;
> + struct ptp_clock *ptp_clock;
> + struct ptp_clock_info ptp_info;
> + struct hwtstamp_config hwtstamp_config;
> + struct mutex ptp_lock;
Just what does this mutex protect? Please add a comment.
Thanks,
Richard
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH net-next 8/8] net: mscc: PTP offloading support
2019-01-18 2:23 ` Richard Cochran
@ 2019-01-18 9:08 ` Antoine Tenart
0 siblings, 0 replies; 16+ messages in thread
From: Antoine Tenart @ 2019-01-18 9:08 UTC (permalink / raw)
To: Richard Cochran
Cc: Antoine Tenart, davem, alexandre.belloni, UNGLinuxDriver, ralf,
paul.burton, jhogan, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
Hi Richard,
On Thu, Jan 17, 2019 at 06:23:43PM -0800, Richard Cochran wrote:
> On Thu, Jan 17, 2019 at 11:02:12AM +0100, Antoine Tenart wrote:
> > This patch adds support for offloading PTP timestamping to the Ocelot
> > switch for both 1-step and 2-step modes.
>
> For PTP Hardware Clock drivers, please add the PTP maintainer onto CC.
Will do for the v2, sorry about that.
> > +static int ocelot_ptp_settime64(struct ptp_clock_info *ptp,
> > + const struct timespec64 *ts)
> > +{
> > + struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
> > + u32 val;
> > +
> > + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
> > + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
> > + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
> > +
> > + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
> > +
> > + ocelot_write_rix(ocelot, lower_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_LSB,
> > + TOD_ACC_PIN);
> > + ocelot_write_rix(ocelot, upper_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_MSB,
> > + TOD_ACC_PIN);
> > + ocelot_write_rix(ocelot, ts->tv_nsec, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
> > +
> > + val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
> > + val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
> > + val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_LOAD);
> > +
> > + ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
>
> You are writing multiple registers. This code is not safe when called
> concurrently.
>
> Ditto for gettime, adjtime, and adjfreq.
Right, I'll fix that.
> > +static int ocelot_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
> > +{
>
> Please implement adjfine instead.
OK, I'll look into it.
> > + struct mutex ptp_lock;
>
> Just what does this mutex protect? Please add a comment.
OK.
Thanks!
Antoine
--
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH net-next 0/8] net: mscc: PTP offloading support
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
` (7 preceding siblings ...)
2019-01-17 10:02 ` [PATCH net-next 8/8] net: mscc: PTP offloading support Antoine Tenart
@ 2019-01-18 2:13 ` Richard Cochran
2019-01-18 9:09 ` Antoine Tenart
2019-01-18 5:07 ` Florian Fainelli
9 siblings, 1 reply; 16+ messages in thread
From: Richard Cochran @ 2019-01-18 2:13 UTC (permalink / raw)
To: Antoine Tenart
Cc: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton,
jhogan, netdev, linux-mips, thomas.petazzoni, quentin.schulz,
allan.nielsen
On Thu, Jan 17, 2019 at 11:02:04AM +0100, Antoine Tenart wrote:
> This series adds support for the PTP offloading support in the Mscc
> Ocelot Ethernet switch driver. Both PTP 1-step and 2-step modes are
> supported.
>
> In order to make use of the PTP offloading support, two new register
> banks were described in the Ocelot device tree. The use of those
> registers by the Mscc Ocelot Ethernet switch driver is made optional for
> dt compatibility reasons. For the same reason a new interrupt is
> described, and its use is also made optinal for compatibility reasons.
> All of this is done ine patches 1-5.
>
> The PTP offloading support itself is added in patch 8.
The subject lines and this description are misleading. You are not
offloading the Precision Time Protocol. Instead, this series
implements a normal PHC driver.
Please change the text to avoid the phrase, "PTP offloading".
Thanks,
Richard
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH net-next 0/8] net: mscc: PTP offloading support
2019-01-18 2:13 ` [PATCH net-next 0/8] " Richard Cochran
@ 2019-01-18 9:09 ` Antoine Tenart
0 siblings, 0 replies; 16+ messages in thread
From: Antoine Tenart @ 2019-01-18 9:09 UTC (permalink / raw)
To: Richard Cochran
Cc: Antoine Tenart, davem, alexandre.belloni, UNGLinuxDriver, ralf,
paul.burton, jhogan, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
Hi Richard,
On Thu, Jan 17, 2019 at 06:13:42PM -0800, Richard Cochran wrote:
> On Thu, Jan 17, 2019 at 11:02:04AM +0100, Antoine Tenart wrote:
> > This series adds support for the PTP offloading support in the Mscc
> > Ocelot Ethernet switch driver. Both PTP 1-step and 2-step modes are
> > supported.
> >
> > In order to make use of the PTP offloading support, two new register
> > banks were described in the Ocelot device tree. The use of those
> > registers by the Mscc Ocelot Ethernet switch driver is made optional for
> > dt compatibility reasons. For the same reason a new interrupt is
> > described, and its use is also made optinal for compatibility reasons.
> > All of this is done ine patches 1-5.
> >
> > The PTP offloading support itself is added in patch 8.
>
> The subject lines and this description are misleading. You are not
> offloading the Precision Time Protocol. Instead, this series
> implements a normal PHC driver.
>
> Please change the text to avoid the phrase, "PTP offloading".
Will do.
Thanks!
Antoine
--
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH net-next 0/8] net: mscc: PTP offloading support
2019-01-17 10:02 [PATCH net-next 0/8] net: mscc: PTP offloading support Antoine Tenart
` (8 preceding siblings ...)
2019-01-18 2:13 ` [PATCH net-next 0/8] " Richard Cochran
@ 2019-01-18 5:07 ` Florian Fainelli
2019-01-18 8:58 ` Antoine Tenart
9 siblings, 1 reply; 16+ messages in thread
From: Florian Fainelli @ 2019-01-18 5:07 UTC (permalink / raw)
To: Antoine Tenart, davem, alexandre.belloni, UNGLinuxDriver, ralf,
paul.burton, jhogan
Cc: netdev, linux-mips, thomas.petazzoni, quentin.schulz, allan.nielsen
On 1/17/2019 2:02 AM, Antoine Tenart wrote:
> Hi all,
>
> This series adds support for the PTP offloading support in the Mscc
> Ocelot Ethernet switch driver. Both PTP 1-step and 2-step modes are
> supported.
>
> In order to make use of the PTP offloading support, two new register
> banks were described in the Ocelot device tree. The use of those
> registers by the Mscc Ocelot Ethernet switch driver is made optional for
> dt compatibility reasons. For the same reason a new interrupt is
> described, and its use is also made optinal for compatibility reasons.
> All of this is done ine patches 1-5.
>
> The PTP offloading support itself is added in patch 8.
>
> While doing this support, a few reworks were done in the Ocelot switch
> driver, in patches 6-7.
>
> Patches 2 and 4 should probably go through the MIPS tree.
Looks like you missed copying netdev on this patch series, do you mind
re-sending there as well?
>
> Thanks!
> Antoine
>
> Antoine Tenart (8):
> Documentation/bindings: net: ocelot: document the VCAP and PTP banks
> MIPS: dts: mscc: describe VCAP and PTP register ranges
> Documentation/bindings: net: ocelot: document the PTP ready IRQ
> MIPS: dts: mscc: describe the PTP ready interrupt
> net: mscc: describe the VCAP and PTP register ranges
> net: mscc: improve the frame header parsing readability
> net: mscc: remove the frame_info cpuq member
> net: mscc: PTP offloading support
>
> .../devicetree/bindings/net/mscc-ocelot.txt | 22 +-
> arch/mips/boot/dts/mscc/ocelot.dtsi | 14 +-
> drivers/net/ethernet/mscc/ocelot.c | 509 +++++++++++++++++-
> drivers/net/ethernet/mscc/ocelot.h | 55 +-
> drivers/net/ethernet/mscc/ocelot_board.c | 150 +++++-
> drivers/net/ethernet/mscc/ocelot_ptp.h | 41 ++
> drivers/net/ethernet/mscc/ocelot_regs.c | 22 +
> drivers/net/ethernet/mscc/ocelot_vcap.h | 104 ++++
> 8 files changed, 877 insertions(+), 40 deletions(-)
> create mode 100644 drivers/net/ethernet/mscc/ocelot_ptp.h
> create mode 100644 drivers/net/ethernet/mscc/ocelot_vcap.h
>
--
Florian
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH net-next 0/8] net: mscc: PTP offloading support
2019-01-18 5:07 ` Florian Fainelli
@ 2019-01-18 8:58 ` Antoine Tenart
2019-01-18 18:16 ` Florian Fainelli
0 siblings, 1 reply; 16+ messages in thread
From: Antoine Tenart @ 2019-01-18 8:58 UTC (permalink / raw)
To: Florian Fainelli
Cc: Antoine Tenart, davem, alexandre.belloni, UNGLinuxDriver, ralf,
paul.burton, jhogan, netdev, linux-mips, thomas.petazzoni,
quentin.schulz, allan.nielsen
Hi Florian,
On Thu, Jan 17, 2019 at 09:07:05PM -0800, Florian Fainelli wrote:
> On 1/17/2019 2:02 AM, Antoine Tenart wrote:
> >
> > This series adds support for the PTP offloading support in the Mscc
> > Ocelot Ethernet switch driver. Both PTP 1-step and 2-step modes are
> > supported.
> >
> > In order to make use of the PTP offloading support, two new register
> > banks were described in the Ocelot device tree. The use of those
> > registers by the Mscc Ocelot Ethernet switch driver is made optional for
> > dt compatibility reasons. For the same reason a new interrupt is
> > described, and its use is also made optinal for compatibility reasons.
> > All of this is done ine patches 1-5.
> >
> > The PTP offloading support itself is added in patch 8.
> >
> > While doing this support, a few reworks were done in the Ocelot switch
> > driver, in patches 6-7.
> >
> > Patches 2 and 4 should probably go through the MIPS tree.
>
> Looks like you missed copying netdev on this patch series, do you mind
> re-sending there as well?
I just checked and netdev is Cc'ed. I'll prepare a v2 to take in account
the comments, so I'll sent it again anyway.
Thanks!
Antoine
--
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH net-next 0/8] net: mscc: PTP offloading support
2019-01-18 8:58 ` Antoine Tenart
@ 2019-01-18 18:16 ` Florian Fainelli
0 siblings, 0 replies; 16+ messages in thread
From: Florian Fainelli @ 2019-01-18 18:16 UTC (permalink / raw)
To: Antoine Tenart
Cc: davem, alexandre.belloni, UNGLinuxDriver, ralf, paul.burton,
jhogan, netdev, linux-mips, thomas.petazzoni, quentin.schulz,
allan.nielsen
On 1/18/19 12:58 AM, Antoine Tenart wrote:
> Hi Florian,
>
> On Thu, Jan 17, 2019 at 09:07:05PM -0800, Florian Fainelli wrote:
>> On 1/17/2019 2:02 AM, Antoine Tenart wrote:
>>>
>>> This series adds support for the PTP offloading support in the Mscc
>>> Ocelot Ethernet switch driver. Both PTP 1-step and 2-step modes are
>>> supported.
>>>
>>> In order to make use of the PTP offloading support, two new register
>>> banks were described in the Ocelot device tree. The use of those
>>> registers by the Mscc Ocelot Ethernet switch driver is made optional for
>>> dt compatibility reasons. For the same reason a new interrupt is
>>> described, and its use is also made optinal for compatibility reasons.
>>> All of this is done ine patches 1-5.
>>>
>>> The PTP offloading support itself is added in patch 8.
>>>
>>> While doing this support, a few reworks were done in the Ocelot switch
>>> driver, in patches 6-7.
>>>
>>> Patches 2 and 4 should probably go through the MIPS tree.
>>
>> Looks like you missed copying netdev on this patch series, do you mind
>> re-sending there as well?
>
> I just checked and netdev is Cc'ed. I'll prepare a v2 to take in account
> the comments, so I'll sent it again anyway.
Indeed, my bad.
--
Florian
^ permalink raw reply [flat|nested] 16+ messages in thread