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