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
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 New Issue