forked from Minki/linux
2e1bf3a765
If phydev->mii_ts is set by the PHY driver, it will always be
overwritten in of_mdiobus_register_phy(). Fix it. Also make sure, that
the unregister() doesn't do anything if the mii_timestamper was provided by
the PHY driver.
Fixes: 1dca22b184
("net: mdio: of: Register discovered MII time stampers.")
Signed-off-by: Michael Walle <michael@walle.cc>
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
133 lines
3.5 KiB
C
133 lines
3.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
//
|
|
// Support for generic time stamping devices on MII buses.
|
|
// Copyright (C) 2018 Richard Cochran <richardcochran@gmail.com>
|
|
//
|
|
|
|
#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;
|
|
|
|
/* 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);
|