Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Support for generic time stamping devices on MII buses.
0004 // Copyright (C) 2018 Richard Cochran <richardcochran@gmail.com>
0005 //
0006 
0007 #include <linux/mii_timestamper.h>
0008 
0009 static LIST_HEAD(mii_timestamping_devices);
0010 static DEFINE_MUTEX(tstamping_devices_lock);
0011 
0012 struct mii_timestamping_desc {
0013     struct list_head list;
0014     struct mii_timestamping_ctrl *ctrl;
0015     struct device *device;
0016 };
0017 
0018 /**
0019  * register_mii_tstamp_controller() - registers an MII time stamping device.
0020  *
0021  * @device: The device to be registered.
0022  * @ctrl:   Pointer to device's control interface.
0023  *
0024  * Returns zero on success or non-zero on failure.
0025  */
0026 int register_mii_tstamp_controller(struct device *device,
0027                    struct mii_timestamping_ctrl *ctrl)
0028 {
0029     struct mii_timestamping_desc *desc;
0030 
0031     desc = kzalloc(sizeof(*desc), GFP_KERNEL);
0032     if (!desc)
0033         return -ENOMEM;
0034 
0035     INIT_LIST_HEAD(&desc->list);
0036     desc->ctrl = ctrl;
0037     desc->device = device;
0038 
0039     mutex_lock(&tstamping_devices_lock);
0040     list_add_tail(&mii_timestamping_devices, &desc->list);
0041     mutex_unlock(&tstamping_devices_lock);
0042 
0043     return 0;
0044 }
0045 EXPORT_SYMBOL(register_mii_tstamp_controller);
0046 
0047 /**
0048  * unregister_mii_tstamp_controller() - unregisters an MII time stamping device.
0049  *
0050  * @device: A device previously passed to register_mii_tstamp_controller().
0051  */
0052 void unregister_mii_tstamp_controller(struct device *device)
0053 {
0054     struct mii_timestamping_desc *desc;
0055     struct list_head *this, *next;
0056 
0057     mutex_lock(&tstamping_devices_lock);
0058     list_for_each_safe(this, next, &mii_timestamping_devices) {
0059         desc = list_entry(this, struct mii_timestamping_desc, list);
0060         if (desc->device == device) {
0061             list_del_init(&desc->list);
0062             kfree(desc);
0063             break;
0064         }
0065     }
0066     mutex_unlock(&tstamping_devices_lock);
0067 }
0068 EXPORT_SYMBOL(unregister_mii_tstamp_controller);
0069 
0070 /**
0071  * register_mii_timestamper - Enables a given port of an MII time stamper.
0072  *
0073  * @node:   The device tree node of the MII time stamp controller.
0074  * @port:   The index of the port to be enabled.
0075  *
0076  * Returns a valid interface on success or ERR_PTR otherwise.
0077  */
0078 struct mii_timestamper *register_mii_timestamper(struct device_node *node,
0079                          unsigned int port)
0080 {
0081     struct mii_timestamper *mii_ts = NULL;
0082     struct mii_timestamping_desc *desc;
0083     struct list_head *this;
0084 
0085     mutex_lock(&tstamping_devices_lock);
0086     list_for_each(this, &mii_timestamping_devices) {
0087         desc = list_entry(this, struct mii_timestamping_desc, list);
0088         if (desc->device->of_node == node) {
0089             mii_ts = desc->ctrl->probe_channel(desc->device, port);
0090             if (!IS_ERR(mii_ts)) {
0091                 mii_ts->device = desc->device;
0092                 get_device(desc->device);
0093             }
0094             break;
0095         }
0096     }
0097     mutex_unlock(&tstamping_devices_lock);
0098 
0099     return mii_ts ? mii_ts : ERR_PTR(-EPROBE_DEFER);
0100 }
0101 EXPORT_SYMBOL(register_mii_timestamper);
0102 
0103 /**
0104  * unregister_mii_timestamper - Disables a given MII time stamper.
0105  *
0106  * @mii_ts: An interface obtained via register_mii_timestamper().
0107  *
0108  */
0109 void unregister_mii_timestamper(struct mii_timestamper *mii_ts)
0110 {
0111     struct mii_timestamping_desc *desc;
0112     struct list_head *this;
0113 
0114     if (!mii_ts)
0115         return;
0116 
0117     /* mii_timestamper statically registered by the PHY driver won't use the
0118      * register_mii_timestamper() and thus don't have ->device set. Don't
0119      * try to unregister these.
0120      */
0121     if (!mii_ts->device)
0122         return;
0123 
0124     mutex_lock(&tstamping_devices_lock);
0125     list_for_each(this, &mii_timestamping_devices) {
0126         desc = list_entry(this, struct mii_timestamping_desc, list);
0127         if (desc->device == mii_ts->device) {
0128             desc->ctrl->release_channel(desc->device, mii_ts);
0129             put_device(desc->device);
0130             break;
0131         }
0132     }
0133     mutex_unlock(&tstamping_devices_lock);
0134 }
0135 EXPORT_SYMBOL(unregister_mii_timestamper);