mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
Merge branch 'net-dsa-Setup-dsa_netdev_ops'
Florian Fainelli says: ==================== net: dsa: Setup dsa_netdev_ops This patch series addresses the overloading of a DSA CPU/management interface's netdev_ops for the purpose of providing useful information from the switch side. Up until now we had duplicated the existing netdev_ops structure and added specific function pointers to return information of interest. Here we have a more controlled way of doing this by involving the specific netdev_ops function pointers that we want to be patched, which is easier for auditing code in the future. As a byproduct we can now maintain netdev_ops pointer comparisons which would be failing before (no known in tree problems because of that though). Let me know if this approach looks reasonable to you and we might do the same with our ethtool_ops overloading as well. Changes in v2: - use static inline int vs. static int inline (Kbuild robot) - fixed typos in patch 4 (Andrew) - avoid using macros (Andrew) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
202a5d5a7a
@ -86,6 +86,18 @@ struct dsa_device_ops {
|
||||
enum dsa_tag_protocol proto;
|
||||
};
|
||||
|
||||
/* This structure defines the control interfaces that are overlayed by the
|
||||
* DSA layer on top of the DSA CPU/management net_device instance. This is
|
||||
* used by the core net_device layer while calling various net_device_ops
|
||||
* function pointers.
|
||||
*/
|
||||
struct dsa_netdevice_ops {
|
||||
int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr,
|
||||
int cmd);
|
||||
int (*ndo_get_phys_port_name)(struct net_device *dev, char *name,
|
||||
size_t len);
|
||||
};
|
||||
|
||||
#define DSA_TAG_DRIVER_ALIAS "dsa_tag-"
|
||||
#define MODULE_ALIAS_DSA_TAG_DRIVER(__proto) \
|
||||
MODULE_ALIAS(DSA_TAG_DRIVER_ALIAS __stringify(__proto##_VALUE))
|
||||
@ -217,7 +229,7 @@ struct dsa_port {
|
||||
/*
|
||||
* Original copy of the master netdev net_device_ops
|
||||
*/
|
||||
const struct net_device_ops *orig_ndo_ops;
|
||||
const struct dsa_netdevice_ops *netdev_ops;
|
||||
|
||||
bool setup;
|
||||
};
|
||||
@ -679,6 +691,63 @@ static inline bool dsa_can_decode(const struct sk_buff *skb,
|
||||
return false;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
static inline int __dsa_netdevice_ops_check(struct net_device *dev)
|
||||
{
|
||||
int err = -EOPNOTSUPP;
|
||||
|
||||
if (!dev->dsa_ptr)
|
||||
return err;
|
||||
|
||||
if (!dev->dsa_ptr->netdev_ops)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dsa_ndo_do_ioctl(struct net_device *dev, struct ifreq *ifr,
|
||||
int cmd)
|
||||
{
|
||||
const struct dsa_netdevice_ops *ops;
|
||||
int err;
|
||||
|
||||
err = __dsa_netdevice_ops_check(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ops = dev->dsa_ptr->netdev_ops;
|
||||
|
||||
return ops->ndo_do_ioctl(dev, ifr, cmd);
|
||||
}
|
||||
|
||||
static inline int dsa_ndo_get_phys_port_name(struct net_device *dev,
|
||||
char *name, size_t len)
|
||||
{
|
||||
const struct dsa_netdevice_ops *ops;
|
||||
int err;
|
||||
|
||||
err = __dsa_netdevice_ops_check(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ops = dev->dsa_ptr->netdev_ops;
|
||||
|
||||
return ops->ndo_get_phys_port_name(dev, name, len);
|
||||
}
|
||||
#else
|
||||
static inline int dsa_ndo_do_ioctl(struct net_device *dev, struct ifreq *ifr,
|
||||
int cmd)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int dsa_ndo_get_phys_port_name(struct net_device *dev,
|
||||
char *name, size_t len)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
void dsa_unregister_switch(struct dsa_switch *ds);
|
||||
int dsa_register_switch(struct dsa_switch *ds);
|
||||
struct dsa_switch *dsa_switch_find(int tree_index, int sw_index);
|
||||
|
@ -98,6 +98,7 @@
|
||||
#include <net/busy_poll.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/stat.h>
|
||||
#include <net/dsa.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/dst_metadata.h>
|
||||
#include <net/pkt_sched.h>
|
||||
@ -8602,6 +8603,10 @@ int dev_get_phys_port_name(struct net_device *dev,
|
||||
const struct net_device_ops *ops = dev->netdev_ops;
|
||||
int err;
|
||||
|
||||
err = dsa_ndo_get_phys_port_name(dev, name, len);
|
||||
if (err == 0 || err != -EOPNOTSUPP)
|
||||
return err;
|
||||
|
||||
if (ops->ndo_get_phys_port_name) {
|
||||
err = ops->ndo_get_phys_port_name(dev, name, len);
|
||||
if (err != -EOPNOTSUPP)
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/dsa.h>
|
||||
#include <net/wext.h>
|
||||
|
||||
/*
|
||||
@ -225,6 +226,26 @@ static int net_hwtstamp_validate(struct ifreq *ifr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dev_do_ioctl(struct net_device *dev,
|
||||
struct ifreq *ifr, unsigned int cmd)
|
||||
{
|
||||
const struct net_device_ops *ops = dev->netdev_ops;
|
||||
int err = -EOPNOTSUPP;
|
||||
|
||||
err = dsa_ndo_do_ioctl(dev, ifr, cmd);
|
||||
if (err == 0 || err != -EOPNOTSUPP)
|
||||
return err;
|
||||
|
||||
if (ops->ndo_do_ioctl) {
|
||||
if (netif_device_present(dev))
|
||||
err = ops->ndo_do_ioctl(dev, ifr, cmd);
|
||||
else
|
||||
err = -ENODEV;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the SIOCxIFxxx calls, inside rtnl_lock()
|
||||
*/
|
||||
@ -323,13 +344,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
|
||||
cmd == SIOCSHWTSTAMP ||
|
||||
cmd == SIOCGHWTSTAMP ||
|
||||
cmd == SIOCWANDEV) {
|
||||
err = -EOPNOTSUPP;
|
||||
if (ops->ndo_do_ioctl) {
|
||||
if (netif_device_present(dev))
|
||||
err = ops->ndo_do_ioctl(dev, ifr, cmd);
|
||||
else
|
||||
err = -ENODEV;
|
||||
}
|
||||
err = dev_do_ioctl(dev, ifr, cmd);
|
||||
} else
|
||||
err = -EINVAL;
|
||||
|
||||
|
@ -220,12 +220,17 @@ static int dsa_master_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cpu_dp->orig_ndo_ops && cpu_dp->orig_ndo_ops->ndo_do_ioctl)
|
||||
err = cpu_dp->orig_ndo_ops->ndo_do_ioctl(dev, ifr, cmd);
|
||||
if (dev->netdev_ops->ndo_do_ioctl)
|
||||
err = dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct dsa_netdevice_ops dsa_netdev_ops = {
|
||||
.ndo_do_ioctl = dsa_master_ioctl,
|
||||
.ndo_get_phys_port_name = dsa_master_get_phys_port_name,
|
||||
};
|
||||
|
||||
static int dsa_master_ethtool_setup(struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *cpu_dp = dev->dsa_ptr;
|
||||
@ -260,38 +265,10 @@ static void dsa_master_ethtool_teardown(struct net_device *dev)
|
||||
cpu_dp->orig_ethtool_ops = NULL;
|
||||
}
|
||||
|
||||
static int dsa_master_ndo_setup(struct net_device *dev)
|
||||
static void dsa_netdev_ops_set(struct net_device *dev,
|
||||
const struct dsa_netdevice_ops *ops)
|
||||
{
|
||||
struct dsa_port *cpu_dp = dev->dsa_ptr;
|
||||
struct dsa_switch *ds = cpu_dp->ds;
|
||||
struct net_device_ops *ops;
|
||||
|
||||
if (dev->netdev_ops->ndo_get_phys_port_name)
|
||||
return 0;
|
||||
|
||||
ops = devm_kzalloc(ds->dev, sizeof(*ops), GFP_KERNEL);
|
||||
if (!ops)
|
||||
return -ENOMEM;
|
||||
|
||||
cpu_dp->orig_ndo_ops = dev->netdev_ops;
|
||||
if (cpu_dp->orig_ndo_ops)
|
||||
memcpy(ops, cpu_dp->orig_ndo_ops, sizeof(*ops));
|
||||
|
||||
ops->ndo_get_phys_port_name = dsa_master_get_phys_port_name;
|
||||
ops->ndo_do_ioctl = dsa_master_ioctl;
|
||||
|
||||
dev->netdev_ops = ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsa_master_ndo_teardown(struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *cpu_dp = dev->dsa_ptr;
|
||||
|
||||
if (cpu_dp->orig_ndo_ops)
|
||||
dev->netdev_ops = cpu_dp->orig_ndo_ops;
|
||||
cpu_dp->orig_ndo_ops = NULL;
|
||||
dev->dsa_ptr->netdev_ops = ops;
|
||||
}
|
||||
|
||||
static ssize_t tagging_show(struct device *d, struct device_attribute *attr,
|
||||
@ -353,9 +330,7 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dsa_master_ndo_setup(dev);
|
||||
if (ret)
|
||||
goto out_err_ethtool_teardown;
|
||||
dsa_netdev_ops_set(dev, &dsa_netdev_ops);
|
||||
|
||||
ret = sysfs_create_group(&dev->dev.kobj, &dsa_group);
|
||||
if (ret)
|
||||
@ -364,8 +339,7 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
|
||||
return ret;
|
||||
|
||||
out_err_ndo_teardown:
|
||||
dsa_master_ndo_teardown(dev);
|
||||
out_err_ethtool_teardown:
|
||||
dsa_netdev_ops_set(dev, NULL);
|
||||
dsa_master_ethtool_teardown(dev);
|
||||
return ret;
|
||||
}
|
||||
@ -373,7 +347,7 @@ out_err_ethtool_teardown:
|
||||
void dsa_master_teardown(struct net_device *dev)
|
||||
{
|
||||
sysfs_remove_group(&dev->dev.kobj, &dsa_group);
|
||||
dsa_master_ndo_teardown(dev);
|
||||
dsa_netdev_ops_set(dev, NULL);
|
||||
dsa_master_ethtool_teardown(dev);
|
||||
dsa_master_reset_mtu(dev);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user