123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- // SPDX-License-Identifier: GPL-2.0
- //
- // Support for generic time stamping devices on MII buses.
- // Copyright (C) 2018 Richard Cochran <[email protected]>
- //
- #include <linux/mii_timestamper.h>
- static LIST_HEAD(mii_timestamping_devices);
- static DEFINE_MUTEX(tstamping_devices_lock);
- struct mii_timestamping_desc {
- struct list_head list;
- struct mii_timestamping_ctrl *ctrl;
- struct device *device;
- };
- /**
- * register_mii_tstamp_controller() - registers an MII time stamping device.
- *
- * @device: The device to be registered.
- * @ctrl: Pointer to device's control interface.
- *
- * Returns zero on success or non-zero on failure.
- */
- int register_mii_tstamp_controller(struct device *device,
- struct mii_timestamping_ctrl *ctrl)
- {
- struct mii_timestamping_desc *desc;
- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
- INIT_LIST_HEAD(&desc->list);
- desc->ctrl = ctrl;
- desc->device = device;
- mutex_lock(&tstamping_devices_lock);
- list_add_tail(&mii_timestamping_devices, &desc->list);
- mutex_unlock(&tstamping_devices_lock);
- return 0;
- }
- EXPORT_SYMBOL(register_mii_tstamp_controller);
- /**
- * unregister_mii_tstamp_controller() - unregisters an MII time stamping device.
- *
- * @device: A device previously passed to register_mii_tstamp_controller().
- */
- void unregister_mii_tstamp_controller(struct device *device)
- {
- struct mii_timestamping_desc *desc;
- struct list_head *this, *next;
- mutex_lock(&tstamping_devices_lock);
- list_for_each_safe(this, next, &mii_timestamping_devices) {
- desc = list_entry(this, struct mii_timestamping_desc, list);
- if (desc->device == device) {
- list_del_init(&desc->list);
- kfree(desc);
- break;
- }
- }
- mutex_unlock(&tstamping_devices_lock);
- }
- EXPORT_SYMBOL(unregister_mii_tstamp_controller);
- /**
- * register_mii_timestamper - Enables a given port of an MII time stamper.
- *
- * @node: The device tree node of the MII time stamp controller.
- * @port: The index of the port to be enabled.
- *
- * Returns a valid interface on success or ERR_PTR otherwise.
- */
- struct mii_timestamper *register_mii_timestamper(struct device_node *node,
- unsigned int port)
- {
- struct mii_timestamper *mii_ts = NULL;
- struct mii_timestamping_desc *desc;
- struct list_head *this;
- mutex_lock(&tstamping_devices_lock);
- list_for_each(this, &mii_timestamping_devices) {
- desc = list_entry(this, struct mii_timestamping_desc, list);
- if (desc->device->of_node == node) {
- mii_ts = desc->ctrl->probe_channel(desc->device, port);
- if (!IS_ERR(mii_ts)) {
- mii_ts->device = desc->device;
- get_device(desc->device);
- }
- break;
- }
- }
- mutex_unlock(&tstamping_devices_lock);
- return mii_ts ? mii_ts : ERR_PTR(-EPROBE_DEFER);
- }
- EXPORT_SYMBOL(register_mii_timestamper);
- /**
- * unregister_mii_timestamper - Disables a given MII time stamper.
- *
- * @mii_ts: An interface obtained via register_mii_timestamper().
- *
- */
- void unregister_mii_timestamper(struct mii_timestamper *mii_ts)
- {
- struct mii_timestamping_desc *desc;
- struct list_head *this;
- if (!mii_ts)
- return;
- /* mii_timestamper statically registered by the PHY driver won't use the
- * register_mii_timestamper() and thus don't have ->device set. Don't
- * try to unregister these.
- */
- if (!mii_ts->device)
- return;
- mutex_lock(&tstamping_devices_lock);
- list_for_each(this, &mii_timestamping_devices) {
- desc = list_entry(this, struct mii_timestamping_desc, list);
- if (desc->device == mii_ts->device) {
- desc->ctrl->release_channel(desc->device, mii_ts);
- put_device(desc->device);
- break;
- }
- }
- mutex_unlock(&tstamping_devices_lock);
- }
- EXPORT_SYMBOL(unregister_mii_timestamper);
|