Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: mscc: ocelot: support PTP Sync one-step timestamping

Although HWTSTAMP_TX_ONESTEP_SYNC existed in ioctl for hardware timestamp
configuration, the PTP Sync one-step timestamping had never been supported.

This patch is to truely support it.

- ocelot_port_txtstamp_request()
This function handles tx timestamp request by storing
ptp_cmd(tx timestamp type) in OCELOT_SKB_CB(skb)->ptp_cmd,
and additionally for two-step timestamp storing ts_id in
OCELOT_SKB_CB(clone)->ptp_cmd.

- ocelot_ptp_rew_op()
During xmit, this function is called to get rew_op (rewriter option) by
checking skb->cb for tx timestamp request, and configure to transmitting.

Non-onestep-Sync packet with one-step timestamp request falls back to use
two-step timestamp.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Yangbo Lu and committed by
David S. Miller
39e5308b 682eaad9

+81 -58
+53
drivers/net/ethernet/mscc/ocelot.c
··· 6 6 */ 7 7 #include <linux/dsa/ocelot.h> 8 8 #include <linux/if_bridge.h> 9 + #include <linux/ptp_classify.h> 9 10 #include <soc/mscc/ocelot_vcap.h> 10 11 #include "ocelot.h" 11 12 #include "ocelot_vcap.h" ··· 547 546 spin_unlock(&ocelot_port->ts_id_lock); 548 547 } 549 548 549 + u32 ocelot_ptp_rew_op(struct sk_buff *skb) 550 + { 551 + struct sk_buff *clone = OCELOT_SKB_CB(skb)->clone; 552 + u8 ptp_cmd = OCELOT_SKB_CB(skb)->ptp_cmd; 553 + u32 rew_op = 0; 554 + 555 + if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP && clone) { 556 + rew_op = ptp_cmd; 557 + rew_op |= OCELOT_SKB_CB(clone)->ts_id << 3; 558 + } else if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) { 559 + rew_op = ptp_cmd; 560 + } 561 + 562 + return rew_op; 563 + } 564 + EXPORT_SYMBOL(ocelot_ptp_rew_op); 565 + 566 + static bool ocelot_ptp_is_onestep_sync(struct sk_buff *skb) 567 + { 568 + struct ptp_header *hdr; 569 + unsigned int ptp_class; 570 + u8 msgtype, twostep; 571 + 572 + ptp_class = ptp_classify_raw(skb); 573 + if (ptp_class == PTP_CLASS_NONE) 574 + return false; 575 + 576 + hdr = ptp_parse_header(skb, ptp_class); 577 + if (!hdr) 578 + return false; 579 + 580 + msgtype = ptp_get_msgtype(hdr, ptp_class); 581 + twostep = hdr->flag_field[0] & 0x2; 582 + 583 + if (msgtype == PTP_MSGTYPE_SYNC && twostep == 0) 584 + return true; 585 + 586 + return false; 587 + } 588 + 550 589 int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port, 551 590 struct sk_buff *skb, 552 591 struct sk_buff **clone) ··· 594 553 struct ocelot_port *ocelot_port = ocelot->ports[port]; 595 554 u8 ptp_cmd = ocelot_port->ptp_cmd; 596 555 556 + /* Store ptp_cmd in OCELOT_SKB_CB(skb)->ptp_cmd */ 557 + if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) { 558 + if (ocelot_ptp_is_onestep_sync(skb)) { 559 + OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd; 560 + return 0; 561 + } 562 + 563 + /* Fall back to two-step timestamping */ 564 + ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; 565 + } 566 + 597 567 if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { 598 568 *clone = skb_clone_sk(skb); 599 569 if (!(*clone)) 600 570 return -ENOMEM; 601 571 602 572 ocelot_port_add_txtstamp_skb(ocelot, port, *clone); 573 + OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd; 603 574 } 604 575 605 576 return 0;
+4 -4
drivers/net/ethernet/mscc/ocelot_net.c
··· 514 514 return NETDEV_TX_OK; 515 515 } 516 516 517 - if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { 518 - rew_op = ocelot_port->ptp_cmd; 519 - rew_op |= OCELOT_SKB_CB(clone)->ts_id << 3; 520 - } 517 + if (clone) 518 + OCELOT_SKB_CB(skb)->clone = clone; 519 + 520 + rew_op = ocelot_ptp_rew_op(skb); 521 521 } 522 522 523 523 ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
+7 -1
include/soc/mscc/ocelot.h
··· 691 691 692 692 struct ocelot_skb_cb { 693 693 struct sk_buff *clone; 694 + u8 ptp_cmd; 694 695 u8 ts_id; 695 696 }; 696 697 ··· 749 748 void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target, 750 749 u32 val, u32 reg, u32 offset); 751 750 752 - /* Packet I/O */ 753 751 #if IS_ENABLED(CONFIG_MSCC_OCELOT_SWITCH_LIB) 754 752 753 + /* Packet I/O */ 755 754 bool ocelot_can_inject(struct ocelot *ocelot, int grp); 756 755 void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp, 757 756 u32 rew_op, struct sk_buff *skb); 758 757 int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **skb); 759 758 void ocelot_drain_cpu_queue(struct ocelot *ocelot, int grp); 760 759 760 + u32 ocelot_ptp_rew_op(struct sk_buff *skb); 761 761 #else 762 762 763 763 static inline bool ocelot_can_inject(struct ocelot *ocelot, int grp) ··· 782 780 { 783 781 } 784 782 783 + static inline u32 ocelot_ptp_rew_op(struct sk_buff *skb) 784 + { 785 + return 0; 786 + } 785 787 #endif 786 788 787 789 /* Hardware initialization */
+2
net/dsa/Kconfig
··· 111 111 112 112 config NET_DSA_TAG_OCELOT 113 113 tristate "Tag driver for Ocelot family of switches, using NPI port" 114 + depends on MSCC_OCELOT_SWITCH_LIB || \ 115 + (MSCC_OCELOT_SWITCH_LIB=n && COMPILE_TEST) 114 116 select PACKING 115 117 help 116 118 Say Y or M if you want to enable NPI tagging for the Ocelot switches
+4 -23
net/dsa/tag_ocelot.c
··· 5 5 #include <soc/mscc/ocelot.h> 6 6 #include "dsa_priv.h" 7 7 8 - static void ocelot_xmit_ptp(struct dsa_port *dp, void *injection, 9 - struct sk_buff *clone) 10 - { 11 - struct ocelot *ocelot = dp->ds->priv; 12 - struct ocelot_port *ocelot_port; 13 - u64 rew_op; 14 - 15 - ocelot_port = ocelot->ports[dp->index]; 16 - rew_op = ocelot_port->ptp_cmd; 17 - 18 - /* Retrieve timestamp ID populated inside OCELOT_SKB_CB(clone)->ts_id 19 - * by ocelot_port_add_txtstamp_skb 20 - */ 21 - if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) 22 - rew_op |= OCELOT_SKB_CB(clone)->ts_id << 3; 23 - 24 - ocelot_ifh_set_rew_op(injection, rew_op); 25 - } 26 - 27 8 static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev, 28 9 __be32 ifh_prefix, void **ifh) 29 10 { 30 11 struct dsa_port *dp = dsa_slave_to_port(netdev); 31 - struct sk_buff *clone = OCELOT_SKB_CB(skb)->clone; 32 12 struct dsa_switch *ds = dp->ds; 33 13 void *injection; 34 14 __be32 *prefix; 15 + u32 rew_op = 0; 35 16 36 17 injection = skb_push(skb, OCELOT_TAG_LEN); 37 18 prefix = skb_push(skb, OCELOT_SHORT_PREFIX_LEN); ··· 23 42 ocelot_ifh_set_src(injection, ds->num_ports); 24 43 ocelot_ifh_set_qos_class(injection, skb->priority); 25 44 26 - /* TX timestamping was requested */ 27 - if (clone) 28 - ocelot_xmit_ptp(dp, injection, clone); 45 + rew_op = ocelot_ptp_rew_op(skb); 46 + if (rew_op) 47 + ocelot_ifh_set_rew_op(injection, rew_op); 29 48 30 49 *ifh = injection; 31 50 }
+11 -30
net/dsa/tag_ocelot_8021q.c
··· 13 13 #include <soc/mscc/ocelot_ptp.h> 14 14 #include "dsa_priv.h" 15 15 16 - static struct sk_buff *ocelot_xmit_ptp(struct dsa_port *dp, 17 - struct sk_buff *skb, 18 - struct sk_buff *clone) 19 - { 20 - struct ocelot *ocelot = dp->ds->priv; 21 - struct ocelot_port *ocelot_port; 22 - int port = dp->index; 23 - u32 rew_op; 24 - 25 - if (!ocelot_can_inject(ocelot, 0)) 26 - return NULL; 27 - 28 - ocelot_port = ocelot->ports[port]; 29 - rew_op = ocelot_port->ptp_cmd; 30 - 31 - /* Retrieve timestamp ID populated inside OCELOT_SKB_CB(clone)->ts_id 32 - * by ocelot_port_add_txtstamp_skb 33 - */ 34 - if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) 35 - rew_op |= OCELOT_SKB_CB(clone)->ts_id << 3; 36 - 37 - ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb); 38 - 39 - return NULL; 40 - } 41 - 42 16 static struct sk_buff *ocelot_xmit(struct sk_buff *skb, 43 17 struct net_device *netdev) 44 18 { ··· 20 46 u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index); 21 47 u16 queue_mapping = skb_get_queue_mapping(skb); 22 48 u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); 23 - struct sk_buff *clone = OCELOT_SKB_CB(skb)->clone; 49 + struct ocelot *ocelot = dp->ds->priv; 50 + int port = dp->index; 51 + u32 rew_op = 0; 24 52 25 - /* TX timestamping was requested, so inject through MMIO */ 26 - if (clone) 27 - return ocelot_xmit_ptp(dp, skb, clone); 53 + rew_op = ocelot_ptp_rew_op(skb); 54 + if (rew_op) { 55 + if (!ocelot_can_inject(ocelot, 0)) 56 + return NULL; 57 + 58 + ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb); 59 + return NULL; 60 + } 28 61 29 62 return dsa_8021q_xmit(skb, netdev, ETH_P_8021Q, 30 63 ((pcp << VLAN_PRIO_SHIFT) | tx_vid));