mii_timestamper.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Support for generic time stamping devices on MII buses.
  4. // Copyright (C) 2018 Richard Cochran <[email protected]>
  5. //
  6. #include <linux/mii_timestamper.h>
  7. static LIST_HEAD(mii_timestamping_devices);
  8. static DEFINE_MUTEX(tstamping_devices_lock);
  9. struct mii_timestamping_desc {
  10. struct list_head list;
  11. struct mii_timestamping_ctrl *ctrl;
  12. struct device *device;
  13. };
  14. /**
  15. * register_mii_tstamp_controller() - registers an MII time stamping device.
  16. *
  17. * @device: The device to be registered.
  18. * @ctrl: Pointer to device's control interface.
  19. *
  20. * Returns zero on success or non-zero on failure.
  21. */
  22. int register_mii_tstamp_controller(struct device *device,
  23. struct mii_timestamping_ctrl *ctrl)
  24. {
  25. struct mii_timestamping_desc *desc;
  26. desc = kzalloc(sizeof(*desc), GFP_KERNEL);
  27. if (!desc)
  28. return -ENOMEM;
  29. INIT_LIST_HEAD(&desc->list);
  30. desc->ctrl = ctrl;
  31. desc->device = device;
  32. mutex_lock(&tstamping_devices_lock);
  33. list_add_tail(&mii_timestamping_devices, &desc->list);
  34. mutex_unlock(&tstamping_devices_lock);
  35. return 0;
  36. }
  37. EXPORT_SYMBOL(register_mii_tstamp_controller);
  38. /**
  39. * unregister_mii_tstamp_controller() - unregisters an MII time stamping device.
  40. *
  41. * @device: A device previously passed to register_mii_tstamp_controller().
  42. */
  43. void unregister_mii_tstamp_controller(struct device *device)
  44. {
  45. struct mii_timestamping_desc *desc;
  46. struct list_head *this, *next;
  47. mutex_lock(&tstamping_devices_lock);
  48. list_for_each_safe(this, next, &mii_timestamping_devices) {
  49. desc = list_entry(this, struct mii_timestamping_desc, list);
  50. if (desc->device == device) {
  51. list_del_init(&desc->list);
  52. kfree(desc);
  53. break;
  54. }
  55. }
  56. mutex_unlock(&tstamping_devices_lock);
  57. }
  58. EXPORT_SYMBOL(unregister_mii_tstamp_controller);
  59. /**
  60. * register_mii_timestamper - Enables a given port of an MII time stamper.
  61. *
  62. * @node: The device tree node of the MII time stamp controller.
  63. * @port: The index of the port to be enabled.
  64. *
  65. * Returns a valid interface on success or ERR_PTR otherwise.
  66. */
  67. struct mii_timestamper *register_mii_timestamper(struct device_node *node,
  68. unsigned int port)
  69. {
  70. struct mii_timestamper *mii_ts = NULL;
  71. struct mii_timestamping_desc *desc;
  72. struct list_head *this;
  73. mutex_lock(&tstamping_devices_lock);
  74. list_for_each(this, &mii_timestamping_devices) {
  75. desc = list_entry(this, struct mii_timestamping_desc, list);
  76. if (desc->device->of_node == node) {
  77. mii_ts = desc->ctrl->probe_channel(desc->device, port);
  78. if (!IS_ERR(mii_ts)) {
  79. mii_ts->device = desc->device;
  80. get_device(desc->device);
  81. }
  82. break;
  83. }
  84. }
  85. mutex_unlock(&tstamping_devices_lock);
  86. return mii_ts ? mii_ts : ERR_PTR(-EPROBE_DEFER);
  87. }
  88. EXPORT_SYMBOL(register_mii_timestamper);
  89. /**
  90. * unregister_mii_timestamper - Disables a given MII time stamper.
  91. *
  92. * @mii_ts: An interface obtained via register_mii_timestamper().
  93. *
  94. */
  95. void unregister_mii_timestamper(struct mii_timestamper *mii_ts)
  96. {
  97. struct mii_timestamping_desc *desc;
  98. struct list_head *this;
  99. if (!mii_ts)
  100. return;
  101. /* mii_timestamper statically registered by the PHY driver won't use the
  102. * register_mii_timestamper() and thus don't have ->device set. Don't
  103. * try to unregister these.
  104. */
  105. if (!mii_ts->device)
  106. return;
  107. mutex_lock(&tstamping_devices_lock);
  108. list_for_each(this, &mii_timestamping_devices) {
  109. desc = list_entry(this, struct mii_timestamping_desc, list);
  110. if (desc->device == mii_ts->device) {
  111. desc->ctrl->release_channel(desc->device, mii_ts);
  112. put_device(desc->device);
  113. break;
  114. }
  115. }
  116. mutex_unlock(&tstamping_devices_lock);
  117. }
  118. EXPORT_SYMBOL(unregister_mii_timestamper);