timestamping.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * PTP 1588 clock support - support for timestamping in PHY devices
  3. *
  4. * Copyright (C) 2010 OMICRON electronics GmbH
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. #include <linux/errqueue.h>
  21. #include <linux/phy.h>
  22. #include <linux/ptp_classify.h>
  23. #include <linux/skbuff.h>
  24. #include <linux/export.h>
  25. static unsigned int classify(const struct sk_buff *skb)
  26. {
  27. if (likely(skb->dev && skb->dev->phydev &&
  28. skb->dev->phydev->drv))
  29. return ptp_classify_raw(skb);
  30. else
  31. return PTP_CLASS_NONE;
  32. }
  33. void skb_clone_tx_timestamp(struct sk_buff *skb)
  34. {
  35. struct phy_device *phydev;
  36. struct sk_buff *clone;
  37. struct sock *sk = skb->sk;
  38. unsigned int type;
  39. if (!sk)
  40. return;
  41. type = classify(skb);
  42. if (type == PTP_CLASS_NONE)
  43. return;
  44. phydev = skb->dev->phydev;
  45. if (likely(phydev->drv->txtstamp)) {
  46. if (!atomic_inc_not_zero(&sk->sk_refcnt))
  47. return;
  48. clone = skb_clone(skb, GFP_ATOMIC);
  49. if (!clone) {
  50. sock_put(sk);
  51. return;
  52. }
  53. clone->sk = sk;
  54. phydev->drv->txtstamp(phydev, clone, type);
  55. }
  56. }
  57. EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
  58. void skb_complete_tx_timestamp(struct sk_buff *skb,
  59. struct skb_shared_hwtstamps *hwtstamps)
  60. {
  61. struct sock *sk = skb->sk;
  62. struct sock_exterr_skb *serr;
  63. int err;
  64. if (!hwtstamps) {
  65. sock_put(sk);
  66. kfree_skb(skb);
  67. return;
  68. }
  69. *skb_hwtstamps(skb) = *hwtstamps;
  70. serr = SKB_EXT_ERR(skb);
  71. memset(serr, 0, sizeof(*serr));
  72. serr->ee.ee_errno = ENOMSG;
  73. serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
  74. skb->sk = NULL;
  75. err = sock_queue_err_skb(sk, skb);
  76. sock_put(sk);
  77. if (err)
  78. kfree_skb(skb);
  79. }
  80. EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
  81. bool skb_defer_rx_timestamp(struct sk_buff *skb)
  82. {
  83. struct phy_device *phydev;
  84. unsigned int type;
  85. if (skb_headroom(skb) < ETH_HLEN)
  86. return false;
  87. __skb_push(skb, ETH_HLEN);
  88. type = classify(skb);
  89. __skb_pull(skb, ETH_HLEN);
  90. if (type == PTP_CLASS_NONE)
  91. return false;
  92. phydev = skb->dev->phydev;
  93. if (likely(phydev->drv->rxtstamp))
  94. return phydev->drv->rxtstamp(phydev, skb, type);
  95. return false;
  96. }
  97. EXPORT_SYMBOL_GPL(skb_defer_rx_timestamp);