mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: phy: Allow pre-declaration of MDIO devices
Allow board support code to collect pre-declarations for MDIO devices by registering them with mdiobus_register_board_info(). SPI and I2C buses have a similar feature, we were missing this for MDIO devices, but this is particularly useful for e.g: MDIO-connected switches which need to provide their port layout (often board-specific) to a MDIO Ethernet switch driver. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									71e0bbde0d
								
							
						
					
					
						commit
						648ea01340
					
				
					 8 changed files with 145 additions and 1 deletions
				
			
		| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
# Makefile for Linux PHY drivers and MDIO bus drivers
 | 
					# Makefile for Linux PHY drivers and MDIO bus drivers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libphy-y			:= phy.o phy_device.o mdio_bus.o mdio_device.o
 | 
					libphy-y			:= phy.o phy_device.o mdio_bus.o mdio_device.o \
 | 
				
			||||||
 | 
									   mdio-boardinfo.o
 | 
				
			||||||
libphy-$(CONFIG_SWPHY)		+= swphy.o
 | 
					libphy-$(CONFIG_SWPHY)		+= swphy.o
 | 
				
			||||||
libphy-$(CONFIG_LED_TRIGGER_PHY)	+= phy_led_triggers.o
 | 
					libphy-$(CONFIG_LED_TRIGGER_PHY)	+= phy_led_triggers.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										86
									
								
								drivers/net/phy/mdio-boardinfo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								drivers/net/phy/mdio-boardinfo.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,86 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * mdio-boardinfo - Collect pre-declarations for MDIO devices
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute  it and/or modify it
 | 
				
			||||||
 | 
					 * under  the terms of  the GNU General  Public License as published by the
 | 
				
			||||||
 | 
					 * Free Software Foundation;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/export.h>
 | 
				
			||||||
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mdio-boardinfo.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static LIST_HEAD(mdio_board_list);
 | 
				
			||||||
 | 
					static DEFINE_MUTEX(mdio_board_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * mdiobus_setup_mdiodev_from_board_info - create and setup MDIO devices
 | 
				
			||||||
 | 
					 * from pre-collected board specific MDIO information
 | 
				
			||||||
 | 
					 * @mdiodev: MDIO device pointer
 | 
				
			||||||
 | 
					 * Context: can sleep
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void mdiobus_setup_mdiodev_from_board_info(struct mii_bus *bus)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mdio_board_entry *be;
 | 
				
			||||||
 | 
						struct mdio_device *mdiodev;
 | 
				
			||||||
 | 
						struct mdio_board_info *bi;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&mdio_board_lock);
 | 
				
			||||||
 | 
						list_for_each_entry(be, &mdio_board_list, list) {
 | 
				
			||||||
 | 
							bi = &be->board_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (strcmp(bus->id, bi->bus_id))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mdiodev = mdio_device_create(bus, bi->mdio_addr);
 | 
				
			||||||
 | 
							if (IS_ERR(mdiodev))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							strncpy(mdiodev->modalias, bi->modalias,
 | 
				
			||||||
 | 
								sizeof(mdiodev->modalias));
 | 
				
			||||||
 | 
							mdiodev->bus_match = mdio_device_bus_match;
 | 
				
			||||||
 | 
							mdiodev->dev.platform_data = (void *)bi->platform_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = mdio_device_register(mdiodev);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								mdio_device_free(mdiodev);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mutex_unlock(&mdio_board_lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * mdio_register_board_info - register MDIO devices for a given board
 | 
				
			||||||
 | 
					 * @info: array of devices descriptors
 | 
				
			||||||
 | 
					 * @n: number of descriptors provided
 | 
				
			||||||
 | 
					 * Context: can sleep
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The board info passed can be marked with __initdata but be pointers
 | 
				
			||||||
 | 
					 * such as platform_data etc. are copied as-is
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int mdiobus_register_board_info(const struct mdio_board_info *info,
 | 
				
			||||||
 | 
									unsigned int n)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mdio_board_entry *be;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						be = kcalloc(n, sizeof(*be), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!be)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < n; i++, be++, info++) {
 | 
				
			||||||
 | 
							memcpy(&be->board_info, info, sizeof(*info));
 | 
				
			||||||
 | 
							mutex_lock(&mdio_board_lock);
 | 
				
			||||||
 | 
							list_add_tail(&be->list, &mdio_board_list);
 | 
				
			||||||
 | 
							mutex_unlock(&mdio_board_lock);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								drivers/net/phy/mdio-boardinfo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								drivers/net/phy/mdio-boardinfo.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * mdio-boardinfo.h - board info interface internal to the mdio_bus
 | 
				
			||||||
 | 
					 * component
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __MDIO_BOARD_INFO_H
 | 
				
			||||||
 | 
					#define __MDIO_BOARD_INFO_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/phy.h>
 | 
				
			||||||
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mdio_board_entry {
 | 
				
			||||||
 | 
						struct list_head	list;
 | 
				
			||||||
 | 
						struct mdio_board_info	board_info;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mdiobus_setup_mdiodev_from_board_info(struct mii_bus *bus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __MDIO_BOARD_INFO_H */
 | 
				
			||||||
| 
						 | 
					@ -41,6 +41,8 @@
 | 
				
			||||||
#define CREATE_TRACE_POINTS
 | 
					#define CREATE_TRACE_POINTS
 | 
				
			||||||
#include <trace/events/mdio.h>
 | 
					#include <trace/events/mdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mdio-boardinfo.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mdiobus_register_device(struct mdio_device *mdiodev)
 | 
					int mdiobus_register_device(struct mdio_device *mdiodev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (mdiodev->bus->mdio_map[mdiodev->addr])
 | 
						if (mdiodev->bus->mdio_map[mdiodev->addr])
 | 
				
			||||||
| 
						 | 
					@ -343,6 +345,8 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mdiobus_setup_mdiodev_from_board_info(bus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bus->state = MDIOBUS_REGISTERED;
 | 
						bus->state = MDIOBUS_REGISTERED;
 | 
				
			||||||
	pr_info("%s: probed\n", bus->name);
 | 
						pr_info("%s: probed\n", bus->name);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,17 @@ static void mdio_device_release(struct device *dev)
 | 
				
			||||||
	kfree(to_mdio_device(dev));
 | 
						kfree(to_mdio_device(dev));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mdio_device_bus_match(struct device *dev, struct device_driver *drv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mdio_device *mdiodev = to_mdio_device(dev);
 | 
				
			||||||
 | 
						struct mdio_driver *mdiodrv = to_mdio_driver(drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mdiodrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return strcmp(mdiodev->modalias, drv->name) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
 | 
					struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mdio_device *mdiodev;
 | 
						struct mdio_device *mdiodev;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
#define __LINUX_MDIO_H__
 | 
					#define __LINUX_MDIO_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <uapi/linux/mdio.h>
 | 
					#include <uapi/linux/mdio.h>
 | 
				
			||||||
 | 
					#include <linux/mod_devicetable.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mii_bus;
 | 
					struct mii_bus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +30,7 @@ struct mdio_device {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const struct dev_pm_ops *pm_ops;
 | 
						const struct dev_pm_ops *pm_ops;
 | 
				
			||||||
	struct mii_bus *bus;
 | 
						struct mii_bus *bus;
 | 
				
			||||||
 | 
						char modalias[MDIO_NAME_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int (*bus_match)(struct device *dev, struct device_driver *drv);
 | 
						int (*bus_match)(struct device *dev, struct device_driver *drv);
 | 
				
			||||||
	void (*device_free)(struct mdio_device *mdiodev);
 | 
						void (*device_free)(struct mdio_device *mdiodev);
 | 
				
			||||||
| 
						 | 
					@ -71,6 +73,7 @@ int mdio_device_register(struct mdio_device *mdiodev);
 | 
				
			||||||
void mdio_device_remove(struct mdio_device *mdiodev);
 | 
					void mdio_device_remove(struct mdio_device *mdiodev);
 | 
				
			||||||
int mdio_driver_register(struct mdio_driver *drv);
 | 
					int mdio_driver_register(struct mdio_driver *drv);
 | 
				
			||||||
void mdio_driver_unregister(struct mdio_driver *drv);
 | 
					void mdio_driver_unregister(struct mdio_driver *drv);
 | 
				
			||||||
 | 
					int mdio_device_bus_match(struct device *dev, struct device_driver *drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline bool mdio_phy_id_is_c45(int phy_id)
 | 
					static inline bool mdio_phy_id_is_c45(int phy_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -501,6 +501,7 @@ struct platform_device_id {
 | 
				
			||||||
	kernel_ulong_t driver_data;
 | 
						kernel_ulong_t driver_data;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MDIO_NAME_SIZE		32
 | 
				
			||||||
#define MDIO_MODULE_PREFIX	"mdio:"
 | 
					#define MDIO_MODULE_PREFIX	"mdio:"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDIO_ID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
 | 
					#define MDIO_ID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -886,6 +886,25 @@ void mdio_bus_exit(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct bus_type mdio_bus_type;
 | 
					extern struct bus_type mdio_bus_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mdio_board_info {
 | 
				
			||||||
 | 
						const char	*bus_id;
 | 
				
			||||||
 | 
						char		modalias[MDIO_NAME_SIZE];
 | 
				
			||||||
 | 
						int		mdio_addr;
 | 
				
			||||||
 | 
						const void	*platform_data;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_PHYLIB)
 | 
				
			||||||
 | 
					int mdiobus_register_board_info(const struct mdio_board_info *info,
 | 
				
			||||||
 | 
									unsigned int n);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline int mdiobus_register_board_info(const struct mdio_board_info *i,
 | 
				
			||||||
 | 
										      unsigned int n)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * module_phy_driver() - Helper macro for registering PHY drivers
 | 
					 * module_phy_driver() - Helper macro for registering PHY drivers
 | 
				
			||||||
 * @__phy_drivers: array of PHY drivers to register
 | 
					 * @__phy_drivers: array of PHY drivers to register
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue