dummy netdev: Allow user to attach PHY to dummy device

This patch provides the option for the user to specify a PHY device name
(as found in /sys/bus/mdio_bus/devices/) which should be associated
with the dummy device.

The user can then use the regular SIOCGMIIREG/SIOCSMIIREG ioctl's to
get/set registers on the PHY (or other devices) attached to the mdio_bus
of the given PHY.

This is used in cases where you have PHY devices (like e.g. an ethernet
witch) in the hardware which are attached to an mdio_bus that doesn't
serve a PHY attached to an actual real ethernet device (MAC).

Signed-off-by: Harald Welte <laforge@gnumonks.org>
Harald Welte 7 years ago
parent ef9225c87d
commit 34af165830

@ -40,8 +40,14 @@
#define DRV_NAME "dummy"
#define DRV_VERSION "1.0"
#define MAX_DUMMIES 6
static int numdummies = 1;
static char *phy_name[MAX_DUMMIES];
struct dummydev_priv {
struct phy_device *phydev;
/* fake multicast ability */
static void set_multicast_list(struct net_device *dev)
@ -112,6 +118,16 @@ static int dummy_change_carrier(struct net_device *dev, bool new_carrier)
return 0;
static int dummy_dev_ioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd)
struct dummydev_priv *priv = netdev_priv(ndev);
if (priv->phydev)
return phy_mii_ioctl(priv->phydev, ifrq, cmd);
static const struct net_device_ops dummy_netdev_ops = {
.ndo_init = dummy_dev_init,
.ndo_uninit = dummy_dev_uninit,
@ -121,6 +137,7 @@ static const struct net_device_ops dummy_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_get_stats64 = dummy_get_stats64,
.ndo_change_carrier = dummy_change_carrier,
.ndo_do_ioctl = dummy_dev_ioctl,
static void dummy_get_drvinfo(struct net_device *dev,
@ -176,17 +193,54 @@ static struct rtnl_link_ops dummy_link_ops __read_mostly = {
/* Number of dummy devices to be set up by this module. */
module_param(numdummies, int, 0);
MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
module_param_array(phy_name, charp, NULL, 0444);
MODULE_PARM_DESC(phy_name, "Attach a PHY with given name to the net_device");
static int match_first_device(struct device *dev, void *data)
const char *name = data;
printk(KERN_INFO "Checking PHY bus device %p(%s)\n", dev, dev_name(dev));
return !strcmp(dev_name(dev), name);
static struct device *get_mdio_by_name(const char *name)
struct device *phy;
phy = bus_find_device(&mdio_bus_type, NULL, (void *)name,
printk(KERN_INFO "Found PHY bus device at %p\n", phy);
return phy;
static int __init dummy_init_one(void)
static int __init dummy_init_one(int i)
struct device *pdev;
struct net_device *dev_dummy;
struct dummydev_priv *priv;
int err;
dev_dummy = alloc_netdev(0, "dummy%d", NET_NAME_UNKNOWN, dummy_setup);
dev_dummy = alloc_netdev(sizeof(struct dummydev_priv), "dummy%d",
NET_NAME_UNKNOWN, dummy_setup);
if (!dev_dummy)
return -ENOMEM;
priv = netdev_priv(dev_dummy);
dev_dummy->rtnl_link_ops = &dummy_link_ops;
if (i < MAX_DUMMIES && phy_name[i]) {
/* find + attach PHY according to name given as module
* parameter */
pdev = get_mdio_by_name(phy_name[i]);
if (!pdev) {
dev_err(&dev_dummy->dev, "Cannot find PHY '%s'\n", phy_name[i]);
err = -EINVAL;
goto err;
priv->phydev = to_phy_device(pdev);
err = register_netdevice(dev_dummy);
if (err < 0)
goto err;
@ -207,7 +261,7 @@ static int __init dummy_init_module(void)
goto out;
for (i = 0; i < numdummies && !err; i++) {
err = dummy_init_one();
err = dummy_init_one(i);
if (err < 0)