linux/drivers/net/phy/mdio_bus.c

// SPDX-License-Identifier: GPL-2.0+
/* MDIO Bus interface
 *
 * Author: Andy Fleming
 *
 * Copyright (c) 2004 Freescale Semiconductor, Inc.
 */

#define pr_fmt(fmt)

#include <linux/delay.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/micrel_phy.h>
#include <linux/mii.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/phy.h>
#include <linux/reset.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>

#define CREATE_TRACE_POINTS
#include <trace/events/mdio.h>

#include "mdio-boardinfo.h"

static int mdiobus_register_gpiod(struct mdio_device *mdiodev)
{}

static int mdiobus_register_reset(struct mdio_device *mdiodev)
{}

int mdiobus_register_device(struct mdio_device *mdiodev)
{}
EXPORT_SYMBOL();

int mdiobus_unregister_device(struct mdio_device *mdiodev)
{}
EXPORT_SYMBOL();

static struct mdio_device *mdiobus_find_device(struct mii_bus *bus, int addr)
{}

struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
{}
EXPORT_SYMBOL();

bool mdiobus_is_registered_device(struct mii_bus *bus, int addr)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_alloc_size - allocate a mii_bus structure
 * @size: extra amount of memory to allocate for private storage.
 * If non-zero, then bus->priv is points to that memory.
 *
 * Description: called by a bus driver to allocate an mii_bus
 * structure to fill in.
 */
struct mii_bus *mdiobus_alloc_size(size_t size)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_release - mii_bus device release callback
 * @d: the target struct device that contains the mii_bus
 *
 * Description: called when the last reference to an mii_bus is
 * dropped, to free the underlying memory.
 */
static void mdiobus_release(struct device *d)
{}

struct mdio_bus_stat_attr {};

static u64 mdio_bus_get_stat(struct mdio_bus_stats *s, unsigned int offset)
{}

static u64 mdio_bus_get_global_stat(struct mii_bus *bus, unsigned int offset)
{}

static ssize_t mdio_bus_stat_field_show(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{}

static ssize_t mdio_bus_device_stat_field_show(struct device *dev,
					       struct device_attribute *attr,
					       char *buf)
{}

#define MDIO_BUS_STATS_ATTR_DECL(field, file)

#define MDIO_BUS_STATS_ATTR(field)

MDIO_BUS_STATS_ATTR(transfers);
MDIO_BUS_STATS_ATTR(errors);
MDIO_BUS_STATS_ATTR(writes);
MDIO_BUS_STATS_ATTR(reads);

#define MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, file)

#define MDIO_BUS_STATS_ADDR_ATTR(field, addr)

#define MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(addr)				\

MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();
MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL();

#define MDIO_BUS_STATS_ADDR_ATTR_GROUP(addr)			\

static struct attribute *mdio_bus_statistics_attrs[] =;

static const struct attribute_group mdio_bus_statistics_group =;

static const struct attribute_group *mdio_bus_groups[] =;

static struct class mdio_bus_class =;

/**
 * mdio_find_bus - Given the name of a mdiobus, find the mii_bus.
 * @mdio_name: The name of a mdiobus.
 *
 * Returns a reference to the mii_bus, or NULL if none found.  The
 * embedded struct device will have its reference count incremented,
 * and this must be put_deviced'ed once the bus is finished with.
 */
struct mii_bus *mdio_find_bus(const char *mdio_name)
{}
EXPORT_SYMBOL();

#if IS_ENABLED(CONFIG_OF_MDIO)
/**
 * of_mdio_find_bus - Given an mii_bus node, find the mii_bus.
 * @mdio_bus_np: Pointer to the mii_bus.
 *
 * Returns a reference to the mii_bus, or NULL if none found.  The
 * embedded struct device will have its reference count incremented,
 * and this must be put once the bus is finished with.
 *
 * Because the association of a device_node and mii_bus is made via
 * of_mdiobus_register(), the mii_bus cannot be found before it is
 * registered with of_mdiobus_register().
 *
 */
struct mii_bus *of_mdio_find_bus(struct device_node *mdio_bus_np)
{}
EXPORT_SYMBOL();

/* Walk the list of subnodes of a mdio bus and look for a node that
 * matches the mdio device's address with its 'reg' property. If
 * found, set the of_node pointer for the mdio device. This allows
 * auto-probed phy devices to be supplied with information passed in
 * via DT.
 * If a PHY package is found, PHY is searched also there.
 */
static int of_mdiobus_find_phy(struct device *dev, struct mdio_device *mdiodev,
			       struct device_node *np)
{}

static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
				    struct mdio_device *mdiodev)
{}
#else /* !IS_ENABLED(CONFIG_OF_MDIO) */
static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio,
					   struct mdio_device *mdiodev)
{
}
#endif

/**
 * mdiobus_create_device - create a full MDIO device given
 * a mdio_board_info structure
 * @bus: MDIO bus to create the devices on
 * @bi: mdio_board_info structure describing the devices
 *
 * Returns 0 on success or < 0 on error.
 */
static int mdiobus_create_device(struct mii_bus *bus,
				 struct mdio_board_info *bi)
{}

static struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr, bool c45)
{}

/**
 * mdiobus_scan_c22 - scan one address on a bus for C22 MDIO devices.
 * @bus: mii_bus to scan
 * @addr: address on bus to scan
 *
 * This function scans one address on the MDIO bus, looking for
 * devices which can be identified using a vendor/product ID in
 * registers 2 and 3. Not all MDIO devices have such registers, but
 * PHY devices typically do. Hence this function assumes anything
 * found is a PHY, or can be treated as a PHY. Other MDIO devices,
 * such as switches, will probably not be found during the scan.
 */
struct phy_device *mdiobus_scan_c22(struct mii_bus *bus, int addr)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_scan_c45 - scan one address on a bus for C45 MDIO devices.
 * @bus: mii_bus to scan
 * @addr: address on bus to scan
 *
 * This function scans one address on the MDIO bus, looking for
 * devices which can be identified using a vendor/product ID in
 * registers 2 and 3. Not all MDIO devices have such registers, but
 * PHY devices typically do. Hence this function assumes anything
 * found is a PHY, or can be treated as a PHY. Other MDIO devices,
 * such as switches, will probably not be found during the scan.
 */
static struct phy_device *mdiobus_scan_c45(struct mii_bus *bus, int addr)
{}

static int mdiobus_scan_bus_c22(struct mii_bus *bus)
{}

static int mdiobus_scan_bus_c45(struct mii_bus *bus)
{}

/* There are some C22 PHYs which do bad things when where is a C45
 * transaction on the bus, like accepting a read themselves, and
 * stomping over the true devices reply, to performing a write to
 * themselves which was intended for another device. Now that C22
 * devices have been found, see if any of them are bad for C45, and if we
 * should skip the C45 scan.
 */
static bool mdiobus_prevent_c45_scan(struct mii_bus *bus)
{}

/**
 * __mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
 * @bus: target mii_bus
 * @owner: module containing bus accessor functions
 *
 * Description: Called by a bus driver to bring up all the PHYs
 *   on a given bus, and attach them to the bus. Drivers should use
 *   mdiobus_register() rather than __mdiobus_register() unless they
 *   need to pass a specific owner module. MDIO devices which are not
 *   PHYs will not be brought up by this function. They are expected
 *   to be explicitly listed in DT and instantiated by of_mdiobus_register().
 *
 * Returns 0 on success or < 0 on error.
 */
int __mdiobus_register(struct mii_bus *bus, struct module *owner)
{}
EXPORT_SYMBOL();

void mdiobus_unregister(struct mii_bus *bus)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_free - free a struct mii_bus
 * @bus: mii_bus to free
 *
 * This function releases the reference to the underlying device
 * object in the mii_bus.  If this is the last reference, the mii_bus
 * will be freed.
 */
void mdiobus_free(struct mii_bus *bus)
{}
EXPORT_SYMBOL();

static void mdiobus_stats_acct(struct mdio_bus_stats *stats, bool op, int ret)
{}

/**
 * __mdiobus_read - Unlocked version of the mdiobus_read function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to read
 *
 * Read a MDIO bus register. Caller must hold the mdio bus lock.
 *
 * NOTE: MUST NOT be called from interrupt context.
 */
int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
{}
EXPORT_SYMBOL();

/**
 * __mdiobus_write - Unlocked version of the mdiobus_write function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to write
 * @val: value to write to @regnum
 *
 * Write a MDIO bus register. Caller must hold the mdio bus lock.
 *
 * NOTE: MUST NOT be called from interrupt context.
 */
int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
{}
EXPORT_SYMBOL();

/**
 * __mdiobus_modify_changed - Unlocked version of the mdiobus_modify function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to modify
 * @mask: bit mask of bits to clear
 * @set: bit mask of bits to set
 *
 * Read, modify, and if any change, write the register value back to the
 * device. Any error returns a negative number.
 *
 * NOTE: MUST NOT be called from interrupt context.
 */
int __mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
			     u16 mask, u16 set)
{}
EXPORT_SYMBOL_GPL();

/**
 * __mdiobus_c45_read - Unlocked version of the mdiobus_c45_read function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @devad: device address to read
 * @regnum: register number to read
 *
 * Read a MDIO bus register. Caller must hold the mdio bus lock.
 *
 * NOTE: MUST NOT be called from interrupt context.
 */
int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum)
{}
EXPORT_SYMBOL();

/**
 * __mdiobus_c45_write - Unlocked version of the mdiobus_write function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @devad: device address to read
 * @regnum: register number to write
 * @val: value to write to @regnum
 *
 * Write a MDIO bus register. Caller must hold the mdio bus lock.
 *
 * NOTE: MUST NOT be called from interrupt context.
 */
int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
			u16 val)
{}
EXPORT_SYMBOL();

/**
 * __mdiobus_c45_modify_changed - Unlocked version of the mdiobus_modify function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @devad: device address to read
 * @regnum: register number to modify
 * @mask: bit mask of bits to clear
 * @set: bit mask of bits to set
 *
 * Read, modify, and if any change, write the register value back to the
 * device. Any error returns a negative number.
 *
 * NOTE: MUST NOT be called from interrupt context.
 */
static int __mdiobus_c45_modify_changed(struct mii_bus *bus, int addr,
					int devad, u32 regnum, u16 mask,
					u16 set)
{}

/**
 * mdiobus_read_nested - Nested version of the mdiobus_read function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to read
 *
 * In case of nested MDIO bus access avoid lockdep false positives by
 * using mutex_lock_nested().
 *
 * NOTE: MUST NOT be called from interrupt context,
 * because the bus read/write functions may wait for an interrupt
 * to conclude the operation.
 */
int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_read - Convenience function for reading a given MII mgmt register
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to read
 *
 * NOTE: MUST NOT be called from interrupt context,
 * because the bus read/write functions may wait for an interrupt
 * to conclude the operation.
 */
int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_c45_read - Convenience function for reading a given MII mgmt register
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @devad: device address to read
 * @regnum: register number to read
 *
 * NOTE: MUST NOT be called from interrupt context,
 * because the bus read/write functions may wait for an interrupt
 * to conclude the operation.
 */
int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_c45_read_nested - Nested version of the mdiobus_c45_read function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @devad: device address to read
 * @regnum: register number to read
 *
 * In case of nested MDIO bus access avoid lockdep false positives by
 * using mutex_lock_nested().
 *
 * NOTE: MUST NOT be called from interrupt context,
 * because the bus read/write functions may wait for an interrupt
 * to conclude the operation.
 */
int mdiobus_c45_read_nested(struct mii_bus *bus, int addr, int devad,
			    u32 regnum)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_write_nested - Nested version of the mdiobus_write function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to write
 * @val: value to write to @regnum
 *
 * In case of nested MDIO bus access avoid lockdep false positives by
 * using mutex_lock_nested().
 *
 * NOTE: MUST NOT be called from interrupt context,
 * because the bus read/write functions may wait for an interrupt
 * to conclude the operation.
 */
int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_write - Convenience function for writing a given MII mgmt register
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to write
 * @val: value to write to @regnum
 *
 * NOTE: MUST NOT be called from interrupt context,
 * because the bus read/write functions may wait for an interrupt
 * to conclude the operation.
 */
int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_c45_write - Convenience function for writing a given MII mgmt register
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @devad: device address to read
 * @regnum: register number to write
 * @val: value to write to @regnum
 *
 * NOTE: MUST NOT be called from interrupt context,
 * because the bus read/write functions may wait for an interrupt
 * to conclude the operation.
 */
int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
		      u16 val)
{}
EXPORT_SYMBOL();

/**
 * mdiobus_c45_write_nested - Nested version of the mdiobus_c45_write function
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @devad: device address to read
 * @regnum: register number to write
 * @val: value to write to @regnum
 *
 * In case of nested MDIO bus access avoid lockdep false positives by
 * using mutex_lock_nested().
 *
 * NOTE: MUST NOT be called from interrupt context,
 * because the bus read/write functions may wait for an interrupt
 * to conclude the operation.
 */
int mdiobus_c45_write_nested(struct mii_bus *bus, int addr, int devad,
			     u32 regnum, u16 val)
{}
EXPORT_SYMBOL();

/*
 * __mdiobus_modify - Convenience function for modifying a given mdio device
 *	register
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to write
 * @mask: bit mask of bits to clear
 * @set: bit mask of bits to set
 */
int __mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask,
		     u16 set)
{}
EXPORT_SYMBOL_GPL();

/**
 * mdiobus_modify - Convenience function for modifying a given mdio device
 *	register
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to write
 * @mask: bit mask of bits to clear
 * @set: bit mask of bits to set
 */
int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask, u16 set)
{}
EXPORT_SYMBOL_GPL();

/**
 * mdiobus_c45_modify - Convenience function for modifying a given mdio device
 *	register
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @devad: device address to read
 * @regnum: register number to write
 * @mask: bit mask of bits to clear
 * @set: bit mask of bits to set
 */
int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum,
		       u16 mask, u16 set)
{}
EXPORT_SYMBOL_GPL();

/**
 * mdiobus_modify_changed - Convenience function for modifying a given mdio
 *	device register and returning if it changed
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @regnum: register number to write
 * @mask: bit mask of bits to clear
 * @set: bit mask of bits to set
 */
int mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
			   u16 mask, u16 set)
{}
EXPORT_SYMBOL_GPL();

/**
 * mdiobus_c45_modify_changed - Convenience function for modifying a given mdio
 *	device register and returning if it changed
 * @bus: the mii_bus struct
 * @addr: the phy address
 * @devad: device address to read
 * @regnum: register number to write
 * @mask: bit mask of bits to clear
 * @set: bit mask of bits to set
 */
int mdiobus_c45_modify_changed(struct mii_bus *bus, int addr, int devad,
			       u32 regnum, u16 mask, u16 set)
{}
EXPORT_SYMBOL_GPL();

/**
 * mdio_bus_match - determine if given MDIO driver supports the given
 *		    MDIO device
 * @dev: target MDIO device
 * @drv: given MDIO driver
 *
 * Description: Given a MDIO device, and a MDIO driver, return 1 if
 *   the driver supports the device.  Otherwise, return 0. This may
 *   require calling the devices own match function, since different classes
 *   of MDIO devices have different match criteria.
 */
static int mdio_bus_match(struct device *dev, const struct device_driver *drv)
{}

static int mdio_uevent(const struct device *dev, struct kobj_uevent_env *env)
{}

static struct attribute *mdio_bus_device_statistics_attrs[] =;

static const struct attribute_group mdio_bus_device_statistics_group =;

static const struct attribute_group *mdio_bus_dev_groups[] =;

const struct bus_type mdio_bus_type =;
EXPORT_SYMBOL();

int __init mdio_bus_init(void)
{}

#if IS_ENABLED(CONFIG_PHYLIB)
void mdio_bus_exit(void)
{}
EXPORT_SYMBOL_GPL();
#else
module_init(mdio_bus_init);
/* no module_exit, intentional */
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MDIO bus/device layer");
#endif