提交 703bdcbc 编写于 作者: D David S. Miller

Merge branch 'devlink-make-ethtool-compat-reliable'

Jakub Kicinski says:

====================
devlink: make ethtool compat reliable

This is a follow up to the series which added device flash
updates via devlink. I went with the approach of adding a
new NDO in the end. It seems to end up looking cleaner.

First patch removes the option to build devlink as a module.
Users can still decide to not build it, but the module option
ends up not being worth the maintenance cost.

Next two patches add a NDO which can be used to ask the driver
to return a devlink instance associated with a given netdev,
instead of iterating over devlink ports. Drivers which implement
this NDO must take into account the potential impact on the
visibility of the devlink instance.

With the new NDO in place we can remove NFP ethtool flash update
code.

Fifth patch makes sure we hold a reference to dev while
callbacks are active.

Last but not least the NULL-check of devlink->ops is moved
to instance allocation time.

Last but not least missing checks for devlink->ops are added.
There is currently no driver registering devlink without ops,
so can just fix this in -next.

v2 (Michal): add netdev_to_devlink() in patch 3.
v3 (Florian):
 - add missing checks for devlink->ops;
 - move locking/holding into devlink_compat_ functions.
v4 (Jiri):
 - hold devlink_mutex around callbacks (patch 2);
 - require non-NULL ops (patch 6).
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
config INFINIBAND_BNXT_RE config INFINIBAND_BNXT_RE
tristate "Broadcom Netxtreme HCA support" tristate "Broadcom Netxtreme HCA support"
depends on ETHERNET && NETDEVICES && PCI && INET && DCB depends on ETHERNET && NETDEVICES && PCI && INET && DCB
depends on MAY_USE_DEVLINK
select NET_VENDOR_BROADCOM select NET_VENDOR_BROADCOM
select BNXT select BNXT
---help--- ---help---
......
...@@ -2,7 +2,6 @@ config MLX4_INFINIBAND ...@@ -2,7 +2,6 @@ config MLX4_INFINIBAND
tristate "Mellanox ConnectX HCA support" tristate "Mellanox ConnectX HCA support"
depends on NETDEVICES && ETHERNET && PCI && INET depends on NETDEVICES && ETHERNET && PCI && INET
depends on INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS depends on INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS
depends on MAY_USE_DEVLINK
select NET_VENDOR_MELLANOX select NET_VENDOR_MELLANOX
select MLX4_CORE select MLX4_CORE
---help--- ---help---
......
...@@ -505,7 +505,6 @@ source "drivers/net/hyperv/Kconfig" ...@@ -505,7 +505,6 @@ source "drivers/net/hyperv/Kconfig"
config NETDEVSIM config NETDEVSIM
tristate "Simulated networking device" tristate "Simulated networking device"
depends on DEBUG_FS depends on DEBUG_FS
depends on MAY_USE_DEVLINK
help help
This driver is a developer testing tool and software model that can This driver is a developer testing tool and software model that can
be used to test various control path networking APIs, especially be used to test various control path networking APIs, especially
......
...@@ -194,7 +194,6 @@ config SYSTEMPORT ...@@ -194,7 +194,6 @@ config SYSTEMPORT
config BNXT config BNXT
tristate "Broadcom NetXtreme-C/E support" tristate "Broadcom NetXtreme-C/E support"
depends on PCI depends on PCI
depends on MAY_USE_DEVLINK
select FW_LOADER select FW_LOADER
select LIBCRC32C select LIBCRC32C
---help--- ---help---
......
...@@ -64,7 +64,6 @@ config CAVIUM_PTP ...@@ -64,7 +64,6 @@ config CAVIUM_PTP
config LIQUIDIO config LIQUIDIO
tristate "Cavium LiquidIO support" tristate "Cavium LiquidIO support"
depends on 64BIT && PCI depends on 64BIT && PCI
depends on MAY_USE_DEVLINK
depends on PCI depends on PCI
imply PTP_1588_CLOCK imply PTP_1588_CLOCK
select FW_LOADER select FW_LOADER
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
config MLX4_EN config MLX4_EN
tristate "Mellanox Technologies 1/10/40Gbit Ethernet support" tristate "Mellanox Technologies 1/10/40Gbit Ethernet support"
depends on MAY_USE_DEVLINK
depends on PCI && NETDEVICES && ETHERNET && INET depends on PCI && NETDEVICES && ETHERNET && INET
select MLX4_CORE select MLX4_CORE
imply PTP_1588_CLOCK imply PTP_1588_CLOCK
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
config MLX5_CORE config MLX5_CORE
tristate "Mellanox 5th generation network adapters (ConnectX series) core driver" tristate "Mellanox 5th generation network adapters (ConnectX series) core driver"
depends on MAY_USE_DEVLINK
depends on PCI depends on PCI
imply PTP_1588_CLOCK imply PTP_1588_CLOCK
imply VXLAN imply VXLAN
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
config MLXSW_CORE config MLXSW_CORE
tristate "Mellanox Technologies Switch ASICs support" tristate "Mellanox Technologies Switch ASICs support"
depends on MAY_USE_DEVLINK
---help--- ---help---
This driver supports Mellanox Technologies Switch ASICs family. This driver supports Mellanox Technologies Switch ASICs family.
......
...@@ -19,7 +19,6 @@ config NFP ...@@ -19,7 +19,6 @@ config NFP
tristate "Netronome(R) NFP4000/NFP6000 NIC driver" tristate "Netronome(R) NFP4000/NFP6000 NIC driver"
depends on PCI && PCI_MSI depends on PCI && PCI_MSI
depends on VXLAN || VXLAN=n depends on VXLAN || VXLAN=n
depends on MAY_USE_DEVLINK
---help--- ---help---
This driver supports the Netronome(R) NFP4000/NFP6000 based This driver supports the Netronome(R) NFP4000/NFP6000 based
cards working as a advanced Ethernet NIC. It works with both cards working as a advanced Ethernet NIC. It works with both
......
...@@ -433,4 +433,6 @@ int nfp_app_nic_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, ...@@ -433,4 +433,6 @@ int nfp_app_nic_vnic_alloc(struct nfp_app *app, struct nfp_net *nn,
int nfp_app_nic_vnic_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, int nfp_app_nic_vnic_init_phy_port(struct nfp_pf *pf, struct nfp_app *app,
struct nfp_net *nn, unsigned int id); struct nfp_net *nn, unsigned int id);
struct devlink *nfp_devlink_get_devlink(struct net_device *netdev);
#endif #endif
...@@ -376,3 +376,14 @@ void nfp_devlink_port_unregister(struct nfp_port *port) ...@@ -376,3 +376,14 @@ void nfp_devlink_port_unregister(struct nfp_port *port)
{ {
devlink_port_unregister(&port->dl_port); devlink_port_unregister(&port->dl_port);
} }
struct devlink *nfp_devlink_get_devlink(struct net_device *netdev)
{
struct nfp_app *app;
app = nfp_app_from_netdev(netdev);
if (!app)
return NULL;
return priv_to_devlink(app->pf);
}
...@@ -3531,6 +3531,7 @@ const struct net_device_ops nfp_net_netdev_ops = { ...@@ -3531,6 +3531,7 @@ const struct net_device_ops nfp_net_netdev_ops = {
.ndo_udp_tunnel_del = nfp_net_del_vxlan_port, .ndo_udp_tunnel_del = nfp_net_del_vxlan_port,
.ndo_bpf = nfp_net_xdp, .ndo_bpf = nfp_net_xdp,
.ndo_get_port_parent_id = nfp_port_get_port_parent_id, .ndo_get_port_parent_id = nfp_port_get_port_parent_id,
.ndo_get_devlink = nfp_devlink_get_devlink,
}; };
/** /**
......
...@@ -1234,28 +1234,6 @@ static int nfp_net_set_channels(struct net_device *netdev, ...@@ -1234,28 +1234,6 @@ static int nfp_net_set_channels(struct net_device *netdev,
return nfp_net_set_num_rings(nn, total_rx, total_tx); return nfp_net_set_num_rings(nn, total_rx, total_tx);
} }
static int
nfp_net_flash_device(struct net_device *netdev, struct ethtool_flash *flash)
{
struct nfp_app *app;
int ret;
if (flash->region != ETHTOOL_FLASH_ALL_REGIONS)
return -EOPNOTSUPP;
app = nfp_app_from_netdev(netdev);
if (!app)
return -EOPNOTSUPP;
dev_hold(netdev);
rtnl_unlock();
ret = nfp_flash_update_common(app->pf, flash->data, NULL);
rtnl_lock();
dev_put(netdev);
return ret;
}
static const struct ethtool_ops nfp_net_ethtool_ops = { static const struct ethtool_ops nfp_net_ethtool_ops = {
.get_drvinfo = nfp_net_get_drvinfo, .get_drvinfo = nfp_net_get_drvinfo,
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
...@@ -1266,7 +1244,6 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { ...@@ -1266,7 +1244,6 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
.get_sset_count = nfp_net_get_sset_count, .get_sset_count = nfp_net_get_sset_count,
.get_rxnfc = nfp_net_get_rxnfc, .get_rxnfc = nfp_net_get_rxnfc,
.set_rxnfc = nfp_net_set_rxnfc, .set_rxnfc = nfp_net_set_rxnfc,
.flash_device = nfp_net_flash_device,
.get_rxfh_indir_size = nfp_net_get_rxfh_indir_size, .get_rxfh_indir_size = nfp_net_get_rxfh_indir_size,
.get_rxfh_key_size = nfp_net_get_rxfh_key_size, .get_rxfh_key_size = nfp_net_get_rxfh_key_size,
.get_rxfh = nfp_net_get_rxfh, .get_rxfh = nfp_net_get_rxfh,
...@@ -1292,7 +1269,6 @@ const struct ethtool_ops nfp_port_ethtool_ops = { ...@@ -1292,7 +1269,6 @@ const struct ethtool_ops nfp_port_ethtool_ops = {
.get_strings = nfp_port_get_strings, .get_strings = nfp_port_get_strings,
.get_ethtool_stats = nfp_port_get_stats, .get_ethtool_stats = nfp_port_get_stats,
.get_sset_count = nfp_port_get_sset_count, .get_sset_count = nfp_port_get_sset_count,
.flash_device = nfp_net_flash_device,
.set_dump = nfp_app_set_dump, .set_dump = nfp_app_set_dump,
.get_dump_flag = nfp_app_get_dump_flag, .get_dump_flag = nfp_app_get_dump_flag,
.get_dump_data = nfp_app_get_dump_data, .get_dump_data = nfp_app_get_dump_data,
......
...@@ -273,6 +273,7 @@ const struct net_device_ops nfp_repr_netdev_ops = { ...@@ -273,6 +273,7 @@ const struct net_device_ops nfp_repr_netdev_ops = {
.ndo_set_features = nfp_port_set_features, .ndo_set_features = nfp_port_set_features,
.ndo_set_mac_address = eth_mac_addr, .ndo_set_mac_address = eth_mac_addr,
.ndo_get_port_parent_id = nfp_port_get_port_parent_id, .ndo_get_port_parent_id = nfp_port_get_port_parent_id,
.ndo_get_devlink = nfp_devlink_get_devlink,
}; };
void void
......
...@@ -941,6 +941,8 @@ struct dev_ifalias { ...@@ -941,6 +941,8 @@ struct dev_ifalias {
char ifalias[]; char ifalias[];
}; };
struct devlink;
/* /*
* This structure defines the management hooks for network devices. * This structure defines the management hooks for network devices.
* The following hooks can be defined; unless noted otherwise, they are * The following hooks can be defined; unless noted otherwise, they are
...@@ -1249,6 +1251,10 @@ struct dev_ifalias { ...@@ -1249,6 +1251,10 @@ struct dev_ifalias {
* that got dropped are freed/returned via xdp_return_frame(). * that got dropped are freed/returned via xdp_return_frame().
* Returns negative number, means general error invoking ndo, meaning * Returns negative number, means general error invoking ndo, meaning
* no frames were xmit'ed and core-caller will free all frames. * no frames were xmit'ed and core-caller will free all frames.
* struct devlink *(*ndo_get_devlink)(struct net_device *dev);
* Get devlink instance associated with a given netdev.
* Called with a reference on the netdevice and devlink locks only,
* rtnl_lock is not held.
*/ */
struct net_device_ops { struct net_device_ops {
int (*ndo_init)(struct net_device *dev); int (*ndo_init)(struct net_device *dev);
...@@ -1447,6 +1453,7 @@ struct net_device_ops { ...@@ -1447,6 +1453,7 @@ struct net_device_ops {
u32 flags); u32 flags);
int (*ndo_xsk_async_xmit)(struct net_device *dev, int (*ndo_xsk_async_xmit)(struct net_device *dev,
u32 queue_id); u32 queue_id);
struct devlink * (*ndo_get_devlink)(struct net_device *dev);
}; };
/** /**
......
...@@ -538,6 +538,15 @@ static inline struct devlink *priv_to_devlink(void *priv) ...@@ -538,6 +538,15 @@ static inline struct devlink *priv_to_devlink(void *priv)
return container_of(priv, struct devlink, priv); return container_of(priv, struct devlink, priv);
} }
static inline struct devlink *netdev_to_devlink(struct net_device *dev)
{
#if IS_ENABLED(CONFIG_NET_DEVLINK)
if (dev->netdev_ops->ndo_get_devlink)
return dev->netdev_ops->ndo_get_devlink(dev);
#endif
return NULL;
}
struct ib_device; struct ib_device;
#if IS_ENABLED(CONFIG_NET_DEVLINK) #if IS_ENABLED(CONFIG_NET_DEVLINK)
...@@ -707,6 +716,10 @@ devlink_health_reporter_priv(struct devlink_health_reporter *reporter); ...@@ -707,6 +716,10 @@ devlink_health_reporter_priv(struct devlink_health_reporter *reporter);
int devlink_health_report(struct devlink_health_reporter *reporter, int devlink_health_report(struct devlink_health_reporter *reporter,
const char *msg, void *priv_ctx); const char *msg, void *priv_ctx);
void devlink_compat_running_version(struct net_device *dev,
char *buf, size_t len);
int devlink_compat_flash_update(struct net_device *dev, const char *file_name);
#else #else
static inline struct devlink *devlink_alloc(const struct devlink_ops *ops, static inline struct devlink *devlink_alloc(const struct devlink_ops *ops,
...@@ -1190,13 +1203,7 @@ devlink_health_report(struct devlink_health_reporter *reporter, ...@@ -1190,13 +1203,7 @@ devlink_health_report(struct devlink_health_reporter *reporter,
{ {
return 0; return 0;
} }
#endif
#if IS_REACHABLE(CONFIG_NET_DEVLINK)
void devlink_compat_running_version(struct net_device *dev,
char *buf, size_t len);
int devlink_compat_flash_update(struct net_device *dev, const char *file_name);
#else
static inline void static inline void
devlink_compat_running_version(struct net_device *dev, char *buf, size_t len) devlink_compat_running_version(struct net_device *dev, char *buf, size_t len)
{ {
......
...@@ -429,21 +429,12 @@ config NET_SOCK_MSG ...@@ -429,21 +429,12 @@ config NET_SOCK_MSG
with the help of BPF programs. with the help of BPF programs.
config NET_DEVLINK config NET_DEVLINK
tristate "Network physical/parent device Netlink interface" bool "Network physical/parent device Netlink interface"
help help
Network physical/parent device Netlink interface provides Network physical/parent device Netlink interface provides
infrastructure to support access to physical chip-wide config and infrastructure to support access to physical chip-wide config and
monitoring. monitoring.
config MAY_USE_DEVLINK
tristate
default m if NET_DEVLINK=m
default y if NET_DEVLINK=y || NET_DEVLINK=n
help
Drivers using the devlink infrastructure should have a dependency
on MAY_USE_DEVLINK to ensure they do not cause link errors when
devlink is a loadable module and the driver using it is built-in.
config PAGE_POOL config PAGE_POOL
bool bool
......
...@@ -723,7 +723,7 @@ static int devlink_port_type_set(struct devlink *devlink, ...@@ -723,7 +723,7 @@ static int devlink_port_type_set(struct devlink *devlink,
{ {
int err; int err;
if (devlink->ops && devlink->ops->port_type_set) { if (devlink->ops->port_type_set) {
if (port_type == DEVLINK_PORT_TYPE_NOTSET) if (port_type == DEVLINK_PORT_TYPE_NOTSET)
return -EINVAL; return -EINVAL;
if (port_type == devlink_port->type) if (port_type == devlink_port->type)
...@@ -760,7 +760,7 @@ static int devlink_port_split(struct devlink *devlink, u32 port_index, ...@@ -760,7 +760,7 @@ static int devlink_port_split(struct devlink *devlink, u32 port_index,
u32 count, struct netlink_ext_ack *extack) u32 count, struct netlink_ext_ack *extack)
{ {
if (devlink->ops && devlink->ops->port_split) if (devlink->ops->port_split)
return devlink->ops->port_split(devlink, port_index, count, return devlink->ops->port_split(devlink, port_index, count,
extack); extack);
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -786,7 +786,7 @@ static int devlink_port_unsplit(struct devlink *devlink, u32 port_index, ...@@ -786,7 +786,7 @@ static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
if (devlink->ops && devlink->ops->port_unsplit) if (devlink->ops->port_unsplit)
return devlink->ops->port_unsplit(devlink, port_index, extack); return devlink->ops->port_unsplit(devlink, port_index, extack);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -961,7 +961,7 @@ static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb, ...@@ -961,7 +961,7 @@ static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
if (err) if (err)
return err; return err;
if (!devlink->ops || !devlink->ops->sb_pool_get) if (!devlink->ops->sb_pool_get)
return -EOPNOTSUPP; return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
...@@ -1017,7 +1017,7 @@ static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg, ...@@ -1017,7 +1017,7 @@ static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
mutex_lock(&devlink_mutex); mutex_lock(&devlink_mutex);
list_for_each_entry(devlink, &devlink_list, list) { list_for_each_entry(devlink, &devlink_list, list) {
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
!devlink->ops || !devlink->ops->sb_pool_get) !devlink->ops->sb_pool_get)
continue; continue;
mutex_lock(&devlink->lock); mutex_lock(&devlink->lock);
list_for_each_entry(devlink_sb, &devlink->sb_list, list) { list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
...@@ -1046,7 +1046,7 @@ static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index, ...@@ -1046,7 +1046,7 @@ static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
{ {
const struct devlink_ops *ops = devlink->ops; const struct devlink_ops *ops = devlink->ops;
if (ops && ops->sb_pool_set) if (ops->sb_pool_set)
return ops->sb_pool_set(devlink, sb_index, pool_index, return ops->sb_pool_set(devlink, sb_index, pool_index,
size, threshold_type); size, threshold_type);
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -1151,7 +1151,7 @@ static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb, ...@@ -1151,7 +1151,7 @@ static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
if (err) if (err)
return err; return err;
if (!devlink->ops || !devlink->ops->sb_port_pool_get) if (!devlink->ops->sb_port_pool_get)
return -EOPNOTSUPP; return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
...@@ -1213,7 +1213,7 @@ static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg, ...@@ -1213,7 +1213,7 @@ static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
mutex_lock(&devlink_mutex); mutex_lock(&devlink_mutex);
list_for_each_entry(devlink, &devlink_list, list) { list_for_each_entry(devlink, &devlink_list, list) {
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
!devlink->ops || !devlink->ops->sb_port_pool_get) !devlink->ops->sb_port_pool_get)
continue; continue;
mutex_lock(&devlink->lock); mutex_lock(&devlink->lock);
list_for_each_entry(devlink_sb, &devlink->sb_list, list) { list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
...@@ -1242,7 +1242,7 @@ static int devlink_sb_port_pool_set(struct devlink_port *devlink_port, ...@@ -1242,7 +1242,7 @@ static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
{ {
const struct devlink_ops *ops = devlink_port->devlink->ops; const struct devlink_ops *ops = devlink_port->devlink->ops;
if (ops && ops->sb_port_pool_set) if (ops->sb_port_pool_set)
return ops->sb_port_pool_set(devlink_port, sb_index, return ops->sb_port_pool_set(devlink_port, sb_index,
pool_index, threshold); pool_index, threshold);
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -1355,7 +1355,7 @@ static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb, ...@@ -1355,7 +1355,7 @@ static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
if (err) if (err)
return err; return err;
if (!devlink->ops || !devlink->ops->sb_tc_pool_bind_get) if (!devlink->ops->sb_tc_pool_bind_get)
return -EOPNOTSUPP; return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
...@@ -1439,7 +1439,7 @@ devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg, ...@@ -1439,7 +1439,7 @@ devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
mutex_lock(&devlink_mutex); mutex_lock(&devlink_mutex);
list_for_each_entry(devlink, &devlink_list, list) { list_for_each_entry(devlink, &devlink_list, list) {
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
!devlink->ops || !devlink->ops->sb_tc_pool_bind_get) !devlink->ops->sb_tc_pool_bind_get)
continue; continue;
mutex_lock(&devlink->lock); mutex_lock(&devlink->lock);
...@@ -1471,7 +1471,7 @@ static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port, ...@@ -1471,7 +1471,7 @@ static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
{ {
const struct devlink_ops *ops = devlink_port->devlink->ops; const struct devlink_ops *ops = devlink_port->devlink->ops;
if (ops && ops->sb_tc_pool_bind_set) if (ops->sb_tc_pool_bind_set)
return ops->sb_tc_pool_bind_set(devlink_port, sb_index, return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
tc_index, pool_type, tc_index, pool_type,
pool_index, threshold); pool_index, threshold);
...@@ -1519,7 +1519,7 @@ static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb, ...@@ -1519,7 +1519,7 @@ static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
struct devlink_sb *devlink_sb = info->user_ptr[1]; struct devlink_sb *devlink_sb = info->user_ptr[1];
const struct devlink_ops *ops = devlink->ops; const struct devlink_ops *ops = devlink->ops;
if (ops && ops->sb_occ_snapshot) if (ops->sb_occ_snapshot)
return ops->sb_occ_snapshot(devlink, devlink_sb->index); return ops->sb_occ_snapshot(devlink, devlink_sb->index);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -1531,7 +1531,7 @@ static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb, ...@@ -1531,7 +1531,7 @@ static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
struct devlink_sb *devlink_sb = info->user_ptr[1]; struct devlink_sb *devlink_sb = info->user_ptr[1];
const struct devlink_ops *ops = devlink->ops; const struct devlink_ops *ops = devlink->ops;
if (ops && ops->sb_occ_max_clear) if (ops->sb_occ_max_clear)
return ops->sb_occ_max_clear(devlink, devlink_sb->index); return ops->sb_occ_max_clear(devlink, devlink_sb->index);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -1594,13 +1594,9 @@ static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb, ...@@ -1594,13 +1594,9 @@ static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
struct genl_info *info) struct genl_info *info)
{ {
struct devlink *devlink = info->user_ptr[0]; struct devlink *devlink = info->user_ptr[0];
const struct devlink_ops *ops = devlink->ops;
struct sk_buff *msg; struct sk_buff *msg;
int err; int err;
if (!ops)
return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
return -ENOMEM; return -ENOMEM;
...@@ -1625,9 +1621,6 @@ static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, ...@@ -1625,9 +1621,6 @@ static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
int err = 0; int err = 0;
u16 mode; u16 mode;
if (!ops)
return -EOPNOTSUPP;
if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) { if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
if (!ops->eswitch_mode_set) if (!ops->eswitch_mode_set)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -3869,7 +3862,7 @@ static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb, ...@@ -3869,7 +3862,7 @@ static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
struct sk_buff *msg; struct sk_buff *msg;
int err; int err;
if (!devlink->ops || !devlink->ops->info_get) if (!devlink->ops->info_get)
return -EOPNOTSUPP; return -EOPNOTSUPP;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
...@@ -5232,6 +5225,9 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size) ...@@ -5232,6 +5225,9 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
{ {
struct devlink *devlink; struct devlink *devlink;
if (WARN_ON(!ops))
return NULL;
devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL); devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
if (!devlink) if (!devlink)
return NULL; return NULL;
...@@ -6091,7 +6087,7 @@ __devlink_param_driverinit_value_set(struct devlink *devlink, ...@@ -6091,7 +6087,7 @@ __devlink_param_driverinit_value_set(struct devlink *devlink,
int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id, int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
union devlink_param_value *init_val) union devlink_param_value *init_val)
{ {
if (!devlink->ops || !devlink->ops->reload) if (!devlink->ops->reload)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return __devlink_param_driverinit_value_get(&devlink->param_list, return __devlink_param_driverinit_value_get(&devlink->param_list,
...@@ -6138,7 +6134,7 @@ int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port, ...@@ -6138,7 +6134,7 @@ int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
{ {
struct devlink *devlink = devlink_port->devlink; struct devlink *devlink = devlink_port->devlink;
if (!devlink->ops || !devlink->ops->reload) if (!devlink->ops->reload)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return __devlink_param_driverinit_value_get(&devlink_port->param_list, return __devlink_param_driverinit_value_get(&devlink_port->param_list,
...@@ -6397,9 +6393,6 @@ static void __devlink_compat_running_version(struct devlink *devlink, ...@@ -6397,9 +6393,6 @@ static void __devlink_compat_running_version(struct devlink *devlink,
struct sk_buff *msg; struct sk_buff *msg;
int rem, err; int rem, err;
if (!devlink->ops->info_get)
return;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
return; return;
...@@ -6431,71 +6424,54 @@ static void __devlink_compat_running_version(struct devlink *devlink, ...@@ -6431,71 +6424,54 @@ static void __devlink_compat_running_version(struct devlink *devlink,
void devlink_compat_running_version(struct net_device *dev, void devlink_compat_running_version(struct net_device *dev,
char *buf, size_t len) char *buf, size_t len)
{ {
struct devlink_port *devlink_port;
struct devlink *devlink; struct devlink *devlink;
dev_hold(dev);
rtnl_unlock();
mutex_lock(&devlink_mutex); mutex_lock(&devlink_mutex);
list_for_each_entry(devlink, &devlink_list, list) { devlink = netdev_to_devlink(dev);
if (!devlink || !devlink->ops->info_get)
goto unlock_list;
mutex_lock(&devlink->lock); mutex_lock(&devlink->lock);
list_for_each_entry(devlink_port, &devlink->port_list, list) { __devlink_compat_running_version(devlink, buf, len);
if (devlink_port->type == DEVLINK_PORT_TYPE_ETH &&
devlink_port->type_dev == dev) {
__devlink_compat_running_version(devlink,
buf, len);
mutex_unlock(&devlink->lock); mutex_unlock(&devlink->lock);
goto out; unlock_list:
}
}
mutex_unlock(&devlink->lock);
}
out:
mutex_unlock(&devlink_mutex); mutex_unlock(&devlink_mutex);
rtnl_lock();
dev_put(dev);
} }
int devlink_compat_flash_update(struct net_device *dev, const char *file_name) int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
{ {
struct devlink_port *devlink_port;
struct devlink *devlink; struct devlink *devlink;
mutex_lock(&devlink_mutex);
list_for_each_entry(devlink, &devlink_list, list) {
mutex_lock(&devlink->lock);
list_for_each_entry(devlink_port, &devlink->port_list, list) {
int ret = -EOPNOTSUPP; int ret = -EOPNOTSUPP;
if (devlink_port->type != DEVLINK_PORT_TYPE_ETH || dev_hold(dev);
devlink_port->type_dev != dev) rtnl_unlock();
continue;
mutex_unlock(&devlink_mutex); mutex_lock(&devlink_mutex);
if (devlink->ops->flash_update) devlink = netdev_to_devlink(dev);
ret = devlink->ops->flash_update(devlink, if (!devlink || !devlink->ops->flash_update)
file_name, goto unlock_list;
NULL, NULL);
mutex_unlock(&devlink->lock); mutex_lock(&devlink->lock);
return ret; ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
}
mutex_unlock(&devlink->lock); mutex_unlock(&devlink->lock);
} unlock_list:
mutex_unlock(&devlink_mutex); mutex_unlock(&devlink_mutex);
return -EOPNOTSUPP; rtnl_lock();
} dev_put(dev);
static int __init devlink_module_init(void) return ret;
{
return genl_register_family(&devlink_nl_family);
} }
static void __exit devlink_module_exit(void) static int __init devlink_init(void)
{ {
genl_unregister_family(&devlink_nl_family); return genl_register_family(&devlink_nl_family);
} }
module_init(devlink_module_init); subsys_initcall(devlink_init);
module_exit(devlink_module_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
MODULE_DESCRIPTION("Network physical device Netlink interface");
MODULE_ALIAS_GENL_FAMILY(DEVLINK_GENL_NAME);
...@@ -805,11 +805,9 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev, ...@@ -805,11 +805,9 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
if (ops->get_eeprom_len) if (ops->get_eeprom_len)
info.eedump_len = ops->get_eeprom_len(dev); info.eedump_len = ops->get_eeprom_len(dev);
rtnl_unlock();
if (!info.fw_version[0]) if (!info.fw_version[0])
devlink_compat_running_version(dev, info.fw_version, devlink_compat_running_version(dev, info.fw_version,
sizeof(info.fw_version)); sizeof(info.fw_version));
rtnl_lock();
if (copy_to_user(useraddr, &info, sizeof(info))) if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT; return -EFAULT;
...@@ -2040,15 +2038,8 @@ static noinline_for_stack int ethtool_flash_device(struct net_device *dev, ...@@ -2040,15 +2038,8 @@ static noinline_for_stack int ethtool_flash_device(struct net_device *dev,
return -EFAULT; return -EFAULT;
efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
if (!dev->ethtool_ops->flash_device) { if (!dev->ethtool_ops->flash_device)
int ret; return devlink_compat_flash_update(dev, efl.data);
rtnl_unlock();
ret = devlink_compat_flash_update(dev, efl.data);
rtnl_lock();
return ret;
}
return dev->ethtool_ops->flash_device(dev, &efl); return dev->ethtool_ops->flash_device(dev, &efl);
} }
......
...@@ -6,7 +6,7 @@ config HAVE_NET_DSA ...@@ -6,7 +6,7 @@ config HAVE_NET_DSA
config NET_DSA config NET_DSA
tristate "Distributed Switch Architecture" tristate "Distributed Switch Architecture"
depends on HAVE_NET_DSA && MAY_USE_DEVLINK depends on HAVE_NET_DSA
depends on BRIDGE || BRIDGE=n depends on BRIDGE || BRIDGE=n
select NET_SWITCHDEV select NET_SWITCHDEV
select PHYLINK select PHYLINK
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册