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