net: dsa: microchip: ptp: add 4 bytes in tail tag when ptp enabled
[linux-2.6-microblaze.git] / net / dsa / tag_ksz.c
index 080e5c3..420a128 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (c) 2017 Microchip Technology
  */
 
+#include <linux/dsa/ksz_common.h>
 #include <linux/etherdevice.h>
 #include <linux/list.h>
 #include <net/dsa.h>
 #define LAN937X_NAME "lan937x"
 
 /* Typically only one byte is used for tail tag. */
+#define KSZ_PTP_TAG_LEN                        4
 #define KSZ_EGRESS_TAG_LEN             1
 #define KSZ_INGRESS_TAG_LEN            1
 
+#define KSZ_HWTS_EN  0
+
+struct ksz_tagger_private {
+       struct ksz_tagger_data data; /* Must be first */
+       unsigned long state;
+};
+
+static struct ksz_tagger_private *
+ksz_tagger_private(struct dsa_switch *ds)
+{
+       return ds->tagger_data;
+}
+
+static void ksz_hwtstamp_set_state(struct dsa_switch *ds, bool on)
+{
+       struct ksz_tagger_private *priv = ksz_tagger_private(ds);
+
+       if (on)
+               set_bit(KSZ_HWTS_EN, &priv->state);
+       else
+               clear_bit(KSZ_HWTS_EN, &priv->state);
+}
+
+static void ksz_disconnect(struct dsa_switch *ds)
+{
+       struct ksz_tagger_private *priv = ds->tagger_data;
+
+       kfree(priv);
+       ds->tagger_data = NULL;
+}
+
+static int ksz_connect(struct dsa_switch *ds)
+{
+       struct ksz_tagger_data *tagger_data;
+       struct ksz_tagger_private *priv;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       /* Export functions for switch driver use */
+       tagger_data = &priv->data;
+       tagger_data->hwtstamp_set_state = ksz_hwtstamp_set_state;
+       ds->tagger_data = priv;
+
+       return 0;
+}
+
 static struct sk_buff *ksz_common_rcv(struct sk_buff *skb,
                                      struct net_device *dev,
                                      unsigned int port, unsigned int len)
@@ -92,10 +142,12 @@ DSA_TAG_DRIVER(ksz8795_netdev_ops);
 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME);
 
 /*
- * For Ingress (Host -> KSZ9477), 2 bytes are added before FCS.
+ * For Ingress (Host -> KSZ9477), 2/6 bytes are added before FCS.
  * ---------------------------------------------------------------------------
- * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes)
+ * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|tag1(1byte)|
+ * FCS(4bytes)
  * ---------------------------------------------------------------------------
+ * ts   : time stamp (Present only if PTP is enabled in the Hardware)
  * tag0 : Prioritization (not used now)
  * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5)
  *
@@ -114,6 +166,21 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME);
 #define KSZ9477_TAIL_TAG_OVERRIDE      BIT(9)
 #define KSZ9477_TAIL_TAG_LOOKUP                BIT(10)
 
+/* Time stamp tag *needs* to be inserted if PTP is enabled in hardware.
+ * Regardless of Whether it is a PTP frame or not.
+ */
+static void ksz_xmit_timestamp(struct dsa_port *dp, struct sk_buff *skb)
+{
+       struct ksz_tagger_private *priv;
+
+       priv = ksz_tagger_private(dp->ds);
+
+       if (!test_bit(KSZ_HWTS_EN, &priv->state))
+               return;
+
+       put_unaligned_be32(0, skb_put(skb, KSZ_PTP_TAG_LEN));
+}
+
 static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
                                    struct net_device *dev)
 {
@@ -126,6 +193,8 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
                return NULL;
 
        /* Tag encoding */
+       ksz_xmit_timestamp(dp, skb);
+
        tag = skb_put(skb, KSZ9477_INGRESS_TAG_LEN);
        addr = skb_mac_header(skb);
 
@@ -158,7 +227,9 @@ static const struct dsa_device_ops ksz9477_netdev_ops = {
        .proto  = DSA_TAG_PROTO_KSZ9477,
        .xmit   = ksz9477_xmit,
        .rcv    = ksz9477_rcv,
-       .needed_tailroom = KSZ9477_INGRESS_TAG_LEN,
+       .connect = ksz_connect,
+       .disconnect = ksz_disconnect,
+       .needed_tailroom = KSZ9477_INGRESS_TAG_LEN + KSZ_PTP_TAG_LEN,
 };
 
 DSA_TAG_DRIVER(ksz9477_netdev_ops);
@@ -178,6 +249,8 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb,
                return NULL;
 
        /* Tag encoding */
+       ksz_xmit_timestamp(dp, skb);
+
        tag = skb_put(skb, KSZ_INGRESS_TAG_LEN);
        addr = skb_mac_header(skb);
 
@@ -194,16 +267,20 @@ static const struct dsa_device_ops ksz9893_netdev_ops = {
        .proto  = DSA_TAG_PROTO_KSZ9893,
        .xmit   = ksz9893_xmit,
        .rcv    = ksz9477_rcv,
-       .needed_tailroom = KSZ_INGRESS_TAG_LEN,
+       .connect = ksz_connect,
+       .disconnect = ksz_disconnect,
+       .needed_tailroom = KSZ_INGRESS_TAG_LEN + KSZ_PTP_TAG_LEN,
 };
 
 DSA_TAG_DRIVER(ksz9893_netdev_ops);
 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893, KSZ9893_NAME);
 
-/* For xmit, 2 bytes are added before FCS.
+/* For xmit, 2/6 bytes are added before FCS.
  * ---------------------------------------------------------------------------
- * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes)
+ * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|tag1(1byte)|
+ * FCS(4bytes)
  * ---------------------------------------------------------------------------
+ * ts   : time stamp (Present only if PTP is enabled in the Hardware)
  * tag0 : represents tag override, lookup and valid
  * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8)
  *
@@ -232,6 +309,8 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb,
        if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
                return NULL;
 
+       ksz_xmit_timestamp(dp, skb);
+
        tag = skb_put(skb, LAN937X_EGRESS_TAG_LEN);
 
        val = BIT(dp->index);
@@ -252,7 +331,9 @@ static const struct dsa_device_ops lan937x_netdev_ops = {
        .proto  = DSA_TAG_PROTO_LAN937X,
        .xmit   = lan937x_xmit,
        .rcv    = ksz9477_rcv,
-       .needed_tailroom = LAN937X_EGRESS_TAG_LEN,
+       .connect = ksz_connect,
+       .disconnect = ksz_disconnect,
+       .needed_tailroom = LAN937X_EGRESS_TAG_LEN + KSZ_PTP_TAG_LEN,
 };
 
 DSA_TAG_DRIVER(lan937x_netdev_ops);