Skip to content

Commit

Permalink
Merge branch 'devlink'
Browse files Browse the repository at this point in the history
Jiri Pirko says:

====================
Introduce devlink interface and first drivers to use it

There a is need for some userspace API that would allow to expose things
that are not directly related to any device class like net_device of
ib_device, but rather chip-wide/switch-ASIC-wide stuff.

Use cases:
1) get/set of port type (Ethernet/InfiniBand)
2) setting up port splitters - split port into multiple ones and squash again,
   enables usage of splitter cable
3) setting up shared buffers - shared among multiple ports within
   one chip (work in progress)
4) configuration of switch wide properties - resources division etc - This will
   allow to pass configuration that is unacceptable to be passed as
   a module option.

First patch of this set introduces a new generic Netlink based interface,
called "devlink". It is similar to nl80211 model and it is heavily
influenced by it, including the API definition. The devlink introduction patch
implements use cases 1) and 2). Other 2 are in development atm and will
be addressed by follow-ups.

It is very convenient for drivers to use devlink, as you can see in other
patches in this set.

Counterpart for devlink is userspace tool for now called "dl". Command line
interface and outputs are derived from "ip" tool so it should be easy
for users to get used to it.

It is available here as a standalone tool for now:
https://github.com/jpirko/devlink
After this is merge in kernel, I will include the "dl" or "devlink" tool
into iproute2 toolset.

Port type setting example:
	myhost:~$ dl help
	Usage: dl [ OPTIONS ] OBJECT { COMMAND | help }
	where  OBJECT := { dev | port | monitor }
	       OPTIONS := { -v/--verbose }

	myhost:~$ dl dev help
	Usage: dl dev show [DEV]

	myhost:~$ dl dev show
	pci/0000:01:00.0

	myhost:~$ dl port help
	Usage: dl port show [DEV/PORT_INDEX]
	Usage: dl port set DEV/PORT_INDEX [ type { eth | ib | auto} ]
	Usage: dl port split DEV/PORT_INDEX count
	Usage: dl port unsplit DEV/PORT_INDEX

	myhost:~$ dl port show
	pci/0000:01:00.0/1: type ib ibdev mlx4_0
	pci/0000:01:00.0/2: type ib ibdev mlx4_0

	myhost:~$ sudo dl port set pci/0000:01:00.0/1 type eth

	myhost:~$ dl port show
	pci/0000:01:00.0/1: type eth netdev ens4
	pci/0000:01:00.0/2: type ib ibdev mlx4_0

	myhost:~$ sudo dl port set ens4 type auto

	myhost:~$ dl port show
	pci/0000:01:00.0/1: type eth(auto) netdev ens4
	pci/0000:01:00.0/2: type ib ibdev mlx4_0

Port splitting example:
	myswitch:~$ sudo modprobe mlxsw_pci
	myswitch:~$ dl port
	pci/0000:03:00.0/1: type eth netdev eth0
	pci/0000:03:00.0/3: type eth netdev eth1
	pci/0000:03:00.0/5: type eth netdev eth2
	...
	pci/0000:03:00.0/63: type eth netdev eth31

	myswitch:~$ sudo dl port split pci/0000:03:00.0/1 2   (or "sudo dl port split eth0 2")

	myswitch:~$ dl port
	pci/0000:03:00.0/3: type eth netdev eth1
	pci/0000:03:00.0/5: type eth netdev eth2
	...
	pci/0000:03:00.0/63: type eth netdev eth31
	pci/0000:03:00.0/1: type eth netdev eth0 split_group 16
	pci/0000:03:00.0/2: type eth netdev eth32 split_group 16

	myswitch:~$ sudo dl port unsplit pci/0000:03:00.0/1

	myswitch:~$ dl port
	pci/0000:03:00.0/3: type eth netdev eth1
	pci/0000:03:00.0/5: type eth netdev eth2
	pci/0000:03:00.0/63: type eth netdev eth31
	pci/0000:03:00.0/1: type eth netdev eth0

v2->v3:
patch 1/9
 -removed generated devlink index and name, use bus name and dev name as
  a handle for all userspace originated commands. Along with that,
  remove sysfs stub. Requested by Hannes Sowa.
patch 2/9
 -add dev param to devlink_register (api change)
patch 4/9
 -add dev param to devlink_register (api change)
patch 9/9
 -set port's speed according to width fix by Ido
v1->v2:
patch 1/9
 -removed no longer used "devlink_dev" helper
 -fix couple of typos and misspells
patch 4/9:
 -removed SET_NETDEV_DEV set to devlink dev
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Mar 1, 2016
2 parents bd070e2 + 18f1e70 commit 7f66ee4
Show file tree
Hide file tree
Showing 18 changed files with 1,425 additions and 59 deletions.
8 changes: 8 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -3499,6 +3499,14 @@ F: include/linux/device-mapper.h
F: include/linux/dm-*.h
F: include/uapi/linux/dm-*.h

DEVLINK
M: Jiri Pirko <jiri@mellanox.com>
L: netdev@vger.kernel.org
S: Supported
F: net/core/devlink.c
F: include/net/devlink.h
F: include/uapi/linux/devlink.h

DIALOG SEMICONDUCTOR DRIVERS
M: Support Opensource <support.opensource@diasemi.com>
W: http://www.dialog-semiconductor.com/products
Expand Down
7 changes: 7 additions & 0 deletions drivers/infiniband/hw/mlx4/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <linux/if_vlan.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
#include <net/devlink.h>

#include <rdma/ib_smi.h>
#include <rdma/ib_user_verbs.h>
Expand Down Expand Up @@ -2519,6 +2520,9 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
}

ibdev->ib_active = true;
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
devlink_port_type_ib_set(mlx4_get_devlink_port(dev, i),
&ibdev->ib_dev);

if (mlx4_is_mfunc(ibdev->dev))
init_pkeys(ibdev);
Expand Down Expand Up @@ -2643,7 +2647,10 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
{
struct mlx4_ib_dev *ibdev = ibdev_ptr;
int p;
int i;

mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
devlink_port_type_clear(mlx4_get_devlink_port(dev, i));
ibdev->ib_active = false;
flush_workqueue(wq);

Expand Down
8 changes: 7 additions & 1 deletion drivers/net/ethernet/mellanox/mlx4/en_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <net/ip.h>
#include <net/busy_poll.h>
#include <net/vxlan.h>
#include <net/devlink.h>

#include <linux/mlx4/driver.h>
#include <linux/mlx4/device.h>
Expand Down Expand Up @@ -2033,8 +2034,11 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port);

/* Unregister device - this will close the port if it was up */
if (priv->registered)
if (priv->registered) {
devlink_port_type_clear(mlx4_get_devlink_port(mdev->dev,
priv->port));
unregister_netdev(dev);
}

if (priv->allocated)
mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE);
Expand Down Expand Up @@ -3051,6 +3055,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}

priv->registered = 1;
devlink_port_type_eth_set(mlx4_get_devlink_port(mdev->dev, priv->port),
dev);

return 0;

Expand Down
9 changes: 9 additions & 0 deletions drivers/net/ethernet/mellanox/mlx4/intf.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/errno.h>
#include <net/devlink.h>

#include "mlx4.h"

Expand Down Expand Up @@ -249,3 +250,11 @@ void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int
return result;
}
EXPORT_SYMBOL_GPL(mlx4_get_protocol_dev);

struct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port)
{
struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];

return &info->devlink_port;
}
EXPORT_SYMBOL_GPL(mlx4_get_devlink_port);
128 changes: 96 additions & 32 deletions drivers/net/ethernet/mellanox/mlx4/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <linux/io-mapping.h>
#include <linux/delay.h>
#include <linux/kmod.h>
#include <net/devlink.h>

#include <linux/mlx4/device.h>
#include <linux/mlx4/doorbell.h>
Expand Down Expand Up @@ -1081,36 +1082,20 @@ static ssize_t show_port_type(struct device *dev,
return strlen(buf);
}

static ssize_t set_port_type(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
static int __set_port_type(struct mlx4_port_info *info,
enum mlx4_port_type port_type)
{
struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
port_attr);
struct mlx4_dev *mdev = info->dev;
struct mlx4_priv *priv = mlx4_priv(mdev);
enum mlx4_port_type types[MLX4_MAX_PORTS];
enum mlx4_port_type new_types[MLX4_MAX_PORTS];
static DEFINE_MUTEX(set_port_type_mutex);
int i;
int err = 0;

mutex_lock(&set_port_type_mutex);

if (!strcmp(buf, "ib\n"))
info->tmp_type = MLX4_PORT_TYPE_IB;
else if (!strcmp(buf, "eth\n"))
info->tmp_type = MLX4_PORT_TYPE_ETH;
else if (!strcmp(buf, "auto\n"))
info->tmp_type = MLX4_PORT_TYPE_AUTO;
else {
mlx4_err(mdev, "%s is not supported port type\n", buf);
err = -EINVAL;
goto err_out;
}

mlx4_stop_sense(mdev);
mutex_lock(&priv->port_mutex);
info->tmp_type = port_type;

/* Possible type is always the one that was delivered */
mdev->caps.possible_type[info->port] = info->tmp_type;

Expand Down Expand Up @@ -1152,6 +1137,37 @@ static ssize_t set_port_type(struct device *dev,
out:
mlx4_start_sense(mdev);
mutex_unlock(&priv->port_mutex);

return err;
}

static ssize_t set_port_type(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
port_attr);
struct mlx4_dev *mdev = info->dev;
enum mlx4_port_type port_type;
static DEFINE_MUTEX(set_port_type_mutex);
int err;

mutex_lock(&set_port_type_mutex);

if (!strcmp(buf, "ib\n")) {
port_type = MLX4_PORT_TYPE_IB;
} else if (!strcmp(buf, "eth\n")) {
port_type = MLX4_PORT_TYPE_ETH;
} else if (!strcmp(buf, "auto\n")) {
port_type = MLX4_PORT_TYPE_AUTO;
} else {
mlx4_err(mdev, "%s is not supported port type\n", buf);
err = -EINVAL;
goto err_out;
}

err = __set_port_type(info, port_type);

err_out:
mutex_unlock(&set_port_type_mutex);

Expand Down Expand Up @@ -2881,8 +2897,13 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)

static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
{
struct devlink *devlink = priv_to_devlink(mlx4_priv(dev));
struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
int err = 0;
int err;

err = devlink_port_register(devlink, &info->devlink_port, port);
if (err)
return err;

info->dev = dev;
info->port = port;
Expand All @@ -2907,6 +2928,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
err = device_create_file(&dev->persist->pdev->dev, &info->port_attr);
if (err) {
mlx4_err(dev, "Failed to create file for port %d\n", port);
devlink_port_unregister(&info->devlink_port);
info->port = -1;
}

Expand Down Expand Up @@ -3678,23 +3700,54 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data,
return err;
}

static int mlx4_devlink_port_type_set(struct devlink_port *devlink_port,
enum devlink_port_type port_type)
{
struct mlx4_port_info *info = container_of(devlink_port,
struct mlx4_port_info,
devlink_port);
enum mlx4_port_type mlx4_port_type;

switch (port_type) {
case DEVLINK_PORT_TYPE_AUTO:
mlx4_port_type = MLX4_PORT_TYPE_AUTO;
break;
case DEVLINK_PORT_TYPE_ETH:
mlx4_port_type = MLX4_PORT_TYPE_ETH;
break;
case DEVLINK_PORT_TYPE_IB:
mlx4_port_type = MLX4_PORT_TYPE_IB;
break;
default:
return -EOPNOTSUPP;
}

return __set_port_type(info, mlx4_port_type);
}

static const struct devlink_ops mlx4_devlink_ops = {
.port_type_set = mlx4_devlink_port_type_set,
};

static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct devlink *devlink;
struct mlx4_priv *priv;
struct mlx4_dev *dev;
int ret;

printk_once(KERN_INFO "%s", mlx4_version);

priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
devlink = devlink_alloc(&mlx4_devlink_ops, sizeof(*priv));
if (!devlink)
return -ENOMEM;
priv = devlink_priv(devlink);

dev = &priv->dev;
dev->persist = kzalloc(sizeof(*dev->persist), GFP_KERNEL);
if (!dev->persist) {
kfree(priv);
return -ENOMEM;
ret = -ENOMEM;
goto err_devlink_free;
}
dev->persist->pdev = pdev;
dev->persist->dev = dev;
Expand All @@ -3703,14 +3756,23 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&dev->persist->device_state_mutex);
mutex_init(&dev->persist->interface_state_mutex);

ret = devlink_register(devlink, &pdev->dev);
if (ret)
goto err_persist_free;

ret = __mlx4_init_one(pdev, id->driver_data, priv);
if (ret) {
kfree(dev->persist);
kfree(priv);
} else {
pci_save_state(pdev);
}
if (ret)
goto err_devlink_unregister;

pci_save_state(pdev);
return 0;

err_devlink_unregister:
devlink_unregister(devlink);
err_persist_free:
kfree(dev->persist);
err_devlink_free:
devlink_free(devlink);
return ret;
}

Expand Down Expand Up @@ -3811,6 +3873,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
struct mlx4_dev *dev = persist->dev;
struct mlx4_priv *priv = mlx4_priv(dev);
struct devlink *devlink = priv_to_devlink(priv);
int active_vfs = 0;

mutex_lock(&persist->interface_state_mutex);
Expand Down Expand Up @@ -3841,8 +3904,9 @@ static void mlx4_remove_one(struct pci_dev *pdev)

pci_release_regions(pdev);
pci_disable_device(pdev);
devlink_unregister(devlink);
kfree(dev->persist);
kfree(priv);
devlink_free(devlink);
pci_set_drvdata(pdev, NULL);
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/mellanox/mlx4/mlx4.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <net/devlink.h>

#include <linux/mlx4/device.h>
#include <linux/mlx4/driver.h>
Expand Down Expand Up @@ -828,6 +829,7 @@ struct mlx4_port_info {
struct mlx4_roce_gid_table gid_table;
int base_qpn;
struct cpu_rmap *rmap;
struct devlink_port devlink_port;
};

struct mlx4_sense {
Expand Down
Loading

0 comments on commit 7f66ee4

Please sign in to comment.