* [PATCH net-next 00/19] Mellanox, mlx5 sub function support
@ 2019-11-07 16:04 Parav Pandit
2019-11-07 16:08 ` [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port Parav Pandit
` (3 more replies)
0 siblings, 4 replies; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:04 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Parav Pandit
Hi Dave, Jiri, Alex,
This series adds the support for mlx5 sub function devices using
mediated device with eswitch switchdev mode.
This series is currently on top of [1], but once [1] is merged to
net-next tree, this series should be resend through usual Saeed's
net-next tree or to netdev net-next.
Mdev alias support patches are already reviewed at vfio/kvm's mailing
list in past. Since mlx5_core driver is first user of the
mdev alias API, those patches are part of this series to merge via
net-next tree.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux.git/log/?h=net-next-mlx5
Also, once Jason Wang's series [9] is merged, mlx5_core driver will be enhanced to
use class id based matching support for mdev devices.
Abstract:
---------
Mellanox ConnectX device supports dynamic creation of sub function which
are equivalent to a PCI function handled by mlx5_core and mlx5_ib drivers.
It has few few differences to PCI function. They are described below in
overview section.
Mellanox sub function capability allows users to create several hundreds
of networking and/or rdma devices without depending on PCI SR-IOV support.
Motivation:
-----------
User wants to use multiple netdevices and rdma devices in a system
without enabling SR-IOV, possibly more number of devices than what
mellanox ConnectX device supports using SR-IOV.
Such devices will have most if not all of the acceleration and offload
capabilities of mlx5, while they are still light weight and don't demand
any dedicated physical resources such as (pci function, MSIX vectors).
Provision such netdevice and/or rdma device to use in bare-metal
server or provision to a container.
In future, map such sub function device to a VM once ConnectX device
supports it. In such case, it should be able to reuse existing
mediated device (mdev) [2] framework of kernel.
Regardless of how a sub function is used, it is desired to lifecycle
such device in unified way, such as using mdev [2].
User wants to have same level of control, visibility, offloads support
as that of current SR-IOV VFs using eswitch switchdev mode for
Ethernet devices.
Overview:
---------
Mellanox ConnectX sub functions are exposed to user as a mediated
device (mdev) [2] as discussed in RFC [3] and further during
netdevconf0x13 at [4].
mlx5 mediated device (mdev) enables users to create multiple netdevices
and/or RDMA devices from single PCI function.
Each mdev maps to a mlx5 sub function.
mlx5 sub function is similar to PCI VF. However it doesn't have its own
PCI function and MSI-X vectors.
mlx5 mdevs share common PCI resources such as PCI BAR region,
MSI-X interrupts.
Each mdev has its own window in the PCI BAR region, which is
accessible only to that mdev and applications using it.
Each mlx5 sub function has its own resource namespace for RDMA resources.
mdevs are supported when eswitch mode of the devlink instance
is in switchdev mode described in devlink documentation [5].
mdev is identified using a UUID defined by RFC 4122.
Each created mdev has unique 12 letters alias. This alias is used to
derive phys_port_name attribute of the corresponding representor
netdevice. This establishes clear link between mdev device, eswitch
port and eswitch representor netdevice.
systemd udev [6] will be enhanced post this work to have predictable
netdevice names based on the unique and predicable mdev alias of the
mdev device.
For example, an Ethernet netdevice of an mdev device having alias
'aliasfoo123' will be persistently named as enmaliasfoo123, where:
<en> for Ethernet
m = mediated device bus
<alias> = unique mdev alias
Design decisions:
-----------------
1. mdev device (and bus) instead of any new subdevice bus is used
after concluding discussion at [7]. This simplifies and eliminates the
need of new bus, also eliminates any vendor specific bus.
2. mdev device is also chosen to not create multiple tools for creating
netdevice, rdma device, devlink port, its representor netdevice and
representor rdma port.
3. mdev device support in eswitch switchdev mode, gives rich isolation
and reuses existing offload infrastructure of iproute2/tc.
4. mdev device also enjoys existing devlink health reporting infrastructure
uniformely for PF, VF and mdev.
5. Persistent naming of mdev's netdevice scheme is discussed and concluded
at [8] using systemwide unique, predicable mdev alias.
6. Unique eswitch port phys_port_name derivation from the mdev alias usage
is concluded at [8].
User commands examples:
-----------------------
- Set eswitch mode as switchdev mode
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
- Create a mdev
Generate a UUID
$ UUID=$(uuidgen)
Create the mdev using UUID
$ echo $UUID > /sys/class/net/ens2f0_p0/device/mdev_supported_types/mlx5_core-local/create
- Unbind a mdev from vfio_mdev driver
$ echo $UUID > /sys/bus/mdev/drivers/vfio_mdev/unbind
- Bind a mdev to mlx5_core driver
$ echo $UUID > /sys/bus/mdev/drivers/mlx5_core/bind
- View netdevice and (optionally) RDMA device in sysfs tree
$ ls -l /sys/bus/mdev/devices/$UUID/net/
$ ls -l /sys/bus/mdev/devices/$UUID/infiniband/
- View netdevice and (optionally) RDMA device using iproute2 tools
$ ip link show
$ rdma dev show
- Query maximum number of mdevs that can be created
$ cat /sys/class/net/ens2f0_p0/device/mdev_supported_types/mlx5_core-local/max_mdevs
- Query remaining number of mdevs that can be created
$ cat /sys/class/net/ens2f0_p0/device/mdev_supported_types/mlx5_core-local/available_instances
- Query an alias of the mdev
$ cat /sys/bus/mdev/devices/$UUID/alias
Security model:
--------------
This section covers security aspects of mlx5 mediated devices at
host level and at network level.
Host side:
- At present mlx5 mdev is meant to be used only in a host.
It is not meant to be mapped to a VM or access by userspace application
using VFIO framework.
Hence, mlx5_core driver doesn't implement any of the VFIO device specific
callback routines.
Hence, mlx5 mediated device cannot be mapped to a VM or to a userspace
application via VFIO framework.
- At present an mlx5 mdev can be accessed by an application through
its netdevice and/or RDMA device.
- mlx5 mdev does not share PCI BAR with its parent PCI function.
- All mlx5 mdevs of a given parent device share a single PCI BAR.
However each mdev device has a small dedicated window of the PCI BAR.
Hence, one mdev device cannot access PCI BAR or any of the resources
of another mdev device.
- Each mlx5 mdev has its own dedicated event queue through which interrupt
notifications are delivered. Hence, one mlx5 mdev cannot enable/disable
interrupts of other mlx5 mdev. mlx5 mdev cannot enable/disable interrupts
of the parent PCI function.
Network side:
- By default the netdevice and the rdma device of mlx5 mdev cannot send or
receive any packets over the network or to any other mlx5 mdev.
- mlx5 mdev follows devlink eswitch and vport model of PCI SR-IOV PF and VFs.
All traffic is dropped by default in this eswitch model.
- Each mlx5 mdev has one eswitch vport representor netdevice and rdma port.
The user must do necessary configuration through such representor to enable
mlx5 mdev to send and/or receive packets.
Patchset summary:
-----------------
Patch 1 to 6 prepare mlx5 core driver to create mdev.
Patch-1 Moves mlx5 devlink port close to eswitch port
Patch-2 implements sub function vport representor handling
Patch-3,4 Introduces mlx5 sub function lifecycle routines
Patch-5 Extended mlx5 eswitch to enable/disable sub function vports
Patch-6 Registers mlx5 driver with mdev subsystem for mdev lifecycle
Patch-7 to 10 enhances mdev subsystem for unique alias generation
Patch-7 introduces sha1 based mdev alias
Patch-8 Ensures mdev alias is unique amlong all mdev devices
Patch-9 Exposes mdev alias in sysfs file for systemd/udev usage
Patch-10 Introduces mdev alias API to be used by vendor driver
Patch-11 Improves mdev to avoid nested locking with mlx5_core driver
and devlink subsystem
Patch-12 Introduces new devlink mdev port flavour
Patch-13 Registers devlink eswitch port for a sub function
Patch-14 to 17 implements mdev driver by reusing most of the mlx5_core
driver
Patch-14 implements sharing IRQ between sub function and parent PCI device
Patch-15 implements load, unload routine for sub function
Patch-16 implements dma ops for mediated device
Patch-17 implements mdev driver to bind to mdev device
Patch-18 Adds documentation for mdev overview, example and security model
Patch-19 extends sample mtty driver for mdev alias generation
[1] https://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux.git/log/?h=net-next-mlx5
[2] https://www.kernel.org/doc/Documentation/vfio-mediated-device.txt
[3] https://lkml.org/lkml/2019/3/8/819
[4] https://netdevconf.org/0x13/session.html?workshop-hardware-offload
[5] http://man7.org/linux/man-pages/man8/devlink-dev.8.html.
[6] https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-net_id.c
[7] https://lkml.org/lkml/2019/3/7/696
[8] https://lkml.org/lkml/2019/8/23/146
[9] https://patchwork.ozlabs.org/patch/1190425
Parav Pandit (14):
net/mlx5: E-switch, Move devlink port close to eswitch port
net/mlx5: Introduce SF life cycle APIs to allocate/free
vfio/mdev: Introduce sha1 based mdev alias
vfio/mdev: Make mdev alias unique among all mdevs
vfio/mdev: Expose mdev alias in sysfs tree
vfio/mdev: Introduce an API mdev_alias
vfio/mdev: Improvise mdev life cycle and parent removal scheme
devlink: Introduce mdev port flavour
net/mlx5: Register SF devlink port
net/mlx5: Add load/unload routines for SF driver binding
net/mlx5: Implement dma ops and params for mediated device
net/mlx5: Add mdev driver to bind to mdev devices
Documentation: net: mlx5: Add mdev usage documentation
mtty: Optionally support mtty alias
Vu Pham (4):
net/mlx5: E-Switch, Add SF vport, vport-rep support
net/mlx5: Introduce SF table framework
net/mlx5: E-Switch, Enable/disable SF's vport during SF life cycle
net/mlx5: Add support for mediated devices in switchdev mode
Yuval Avnery (1):
net/mlx5: Share irqs between SFs and parent PCI device
.../driver-api/vfio-mediated-device.rst | 9 +
.../device_drivers/mellanox/mlx5.rst | 122 +++++
.../net/ethernet/mellanox/mlx5/core/Kconfig | 11 +
.../net/ethernet/mellanox/mlx5/core/Makefile | 4 +
drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 6 +
drivers/net/ethernet/mellanox/mlx5/core/dev.c | 17 +
.../net/ethernet/mellanox/mlx5/core/devlink.c | 69 +++
.../net/ethernet/mellanox/mlx5/core/devlink.h | 8 +
.../net/ethernet/mellanox/mlx5/core/en_rep.c | 94 +---
.../net/ethernet/mellanox/mlx5/core/en_rep.h | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/eq.c | 6 +-
.../net/ethernet/mellanox/mlx5/core/eswitch.c | 24 +-
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 85 ++++
.../mellanox/mlx5/core/eswitch_offloads.c | 147 +++++-
.../net/ethernet/mellanox/mlx5/core/lib/eq.h | 3 +-
.../net/ethernet/mellanox/mlx5/core/main.c | 80 +++-
.../ethernet/mellanox/mlx5/core/meddev/mdev.c | 212 +++++++++
.../mellanox/mlx5/core/meddev/mdev_driver.c | 50 +++
.../ethernet/mellanox/mlx5/core/meddev/sf.c | 425 ++++++++++++++++++
.../ethernet/mellanox/mlx5/core/meddev/sf.h | 73 +++
.../ethernet/mellanox/mlx5/core/mlx5_core.h | 54 +++
.../net/ethernet/mellanox/mlx5/core/pci_irq.c | 12 +
.../net/ethernet/mellanox/mlx5/core/vport.c | 4 +-
drivers/vfio/mdev/mdev_core.c | 198 +++++++-
drivers/vfio/mdev/mdev_private.h | 8 +-
drivers/vfio/mdev/mdev_sysfs.c | 26 +-
include/linux/mdev.h | 5 +
include/linux/mlx5/driver.h | 8 +-
include/net/devlink.h | 9 +
include/uapi/linux/devlink.h | 5 +
net/core/devlink.c | 32 ++
samples/vfio-mdev/mtty.c | 13 +
32 files changed, 1678 insertions(+), 143 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/meddev/mdev.c
create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/meddev/mdev_driver.c
create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
--
2.19.2
^ permalink raw reply [flat|nested] 132+ messages in thread
* [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port
2019-11-07 16:04 [PATCH net-next 00/19] Mellanox, mlx5 sub function support Parav Pandit
@ 2019-11-07 16:08 ` Parav Pandit
2019-11-07 16:08 ` [PATCH net-next 02/19] net/mlx5: E-Switch, Add SF vport, vport-rep support Parav Pandit
` (18 more replies)
2019-11-07 17:03 ` [PATCH net-next 00/19] Mellanox, mlx5 sub function support Leon Romanovsky
` (2 subsequent siblings)
3 siblings, 19 replies; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:08 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Parav Pandit
Currently devlink ports are tied to netdev representor.
mlx5_vport structure is better container of e-switch vport
compare to mlx5e_rep_priv.
This enables to extend mlx5_vport easily for mdev flavour.
Hence, move devlink_port from netdev representor to mlx5_vport.
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Parav Pandit <parav@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/devlink.c | 63 +++++++++++++
.../net/ethernet/mellanox/mlx5/core/devlink.h | 8 ++
.../net/ethernet/mellanox/mlx5/core/en_rep.c | 94 +++----------------
.../net/ethernet/mellanox/mlx5/core/en_rep.h | 2 +-
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 1 +
5 files changed, 88 insertions(+), 80 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
index 381925c90d94..ce4278dfc101 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -226,3 +226,66 @@ void mlx5_devlink_unregister(struct devlink *devlink)
ARRAY_SIZE(mlx5_devlink_params));
devlink_unregister(devlink);
}
+
+bool
+mlx5_devlink_port_supported(const struct mlx5_core_dev *dev,
+ const struct mlx5_vport *vport)
+{
+ return vport->vport == MLX5_VPORT_UPLINK ||
+ vport->vport == MLX5_VPORT_PF ||
+ mlx5_eswitch_is_vf_vport(dev->priv.eswitch, vport->vport);
+}
+
+static unsigned int
+vport_to_devlink_port_index(const struct mlx5_core_dev *dev, u16 vport_num)
+{
+ return (MLX5_CAP_GEN(dev, vhca_id) << 16) | vport_num;
+}
+
+static void get_port_switch_id(struct mlx5_core_dev *dev,
+ struct netdev_phys_item_id *ppid)
+{
+ u64 parent_id;
+
+ parent_id = mlx5_query_nic_system_image_guid(dev);
+ ppid->id_len = sizeof(parent_id);
+ memcpy(ppid->id, &parent_id, sizeof(parent_id));
+}
+
+int mlx5_devlink_port_register(struct mlx5_core_dev *dev,
+ struct mlx5_vport *vport)
+{
+ struct devlink *devlink = priv_to_devlink(dev);
+ struct netdev_phys_item_id ppid = {};
+ unsigned int dl_port_index = 0;
+
+ if (!mlx5_devlink_port_supported(dev, vport))
+ return 0;
+
+ get_port_switch_id(dev, &ppid);
+ memset(&vport->dl_port, 0, sizeof(vport->dl_port));
+
+ dl_port_index = vport_to_devlink_port_index(dev, vport->vport);
+ if (vport->vport == MLX5_VPORT_UPLINK)
+ devlink_port_attrs_set(&vport->dl_port,
+ DEVLINK_PORT_FLAVOUR_PHYSICAL,
+ PCI_FUNC(dev->pdev->devfn), false, 0,
+ &ppid.id[0], ppid.id_len);
+ else if (vport->vport == MLX5_VPORT_PF)
+ devlink_port_attrs_pci_pf_set(&vport->dl_port,
+ &ppid.id[0], ppid.id_len,
+ dev->pdev->devfn);
+ else if (mlx5_eswitch_is_vf_vport(dev->priv.eswitch, vport->vport))
+ devlink_port_attrs_pci_vf_set(&vport->dl_port,
+ &ppid.id[0], ppid.id_len,
+ dev->pdev->devfn,
+ vport->vport - 1);
+ return devlink_port_register(devlink, &vport->dl_port, dl_port_index);
+}
+
+void mlx5_devlink_port_unregister(struct mlx5_core_dev *dev,
+ struct mlx5_vport *vport)
+{
+ if (mlx5_devlink_port_supported(dev, vport))
+ devlink_port_unregister(&vport->dl_port);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.h b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
index d0ba03774ddf..b30ea3ca612b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
@@ -5,10 +5,18 @@
#define __MLX5_DEVLINK_H__
#include <net/devlink.h>
+#include "eswitch.h"
struct devlink *mlx5_devlink_alloc(void);
void mlx5_devlink_free(struct devlink *devlink);
int mlx5_devlink_register(struct devlink *devlink, struct device *dev);
void mlx5_devlink_unregister(struct devlink *devlink);
+bool
+mlx5_devlink_port_supported(const struct mlx5_core_dev *dev,
+ const struct mlx5_vport *vport);
+int mlx5_devlink_port_register(struct mlx5_core_dev *dev,
+ struct mlx5_vport *vport);
+void mlx5_devlink_port_unregister(struct mlx5_core_dev *dev,
+ struct mlx5_vport *vport);
#endif /* __MLX5_DEVLINK_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 95892a3b63a1..55f2a707c703 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -392,19 +392,6 @@ static const struct ethtool_ops mlx5e_uplink_rep_ethtool_ops = {
.set_pauseparam = mlx5e_uplink_rep_set_pauseparam,
};
-static void mlx5e_rep_get_port_parent_id(struct net_device *dev,
- struct netdev_phys_item_id *ppid)
-{
- struct mlx5e_priv *priv;
- u64 parent_id;
-
- priv = netdev_priv(dev);
-
- parent_id = mlx5_query_nic_system_image_guid(priv->mdev);
- ppid->id_len = sizeof(parent_id);
- memcpy(ppid->id, &parent_id, sizeof(parent_id));
-}
-
static void mlx5e_sqs2vport_stop(struct mlx5_eswitch *esw,
struct mlx5_eswitch_rep *rep)
{
@@ -1356,8 +1343,11 @@ static struct devlink_port *mlx5e_get_devlink_port(struct net_device *dev)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5e_rep_priv *rpriv = priv->ppriv;
+ struct mlx5_core_dev *mdev = priv->mdev;
+ struct mlx5_vport *vport;
- return &rpriv->dl_port;
+ vport = mlx5_eswitch_get_vport(mdev->priv.eswitch, rpriv->rep->vport);
+ return &vport->dl_port;
}
static const struct net_device_ops mlx5e_netdev_ops_rep = {
@@ -1792,64 +1782,6 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
.rq_groups = MLX5E_NUM_RQ_GROUPS(REGULAR),
};
-static bool
-is_devlink_port_supported(const struct mlx5_core_dev *dev,
- const struct mlx5e_rep_priv *rpriv)
-{
- return rpriv->rep->vport == MLX5_VPORT_UPLINK ||
- rpriv->rep->vport == MLX5_VPORT_PF ||
- mlx5_eswitch_is_vf_vport(dev->priv.eswitch, rpriv->rep->vport);
-}
-
-static unsigned int
-vport_to_devlink_port_index(const struct mlx5_core_dev *dev, u16 vport_num)
-{
- return (MLX5_CAP_GEN(dev, vhca_id) << 16) | vport_num;
-}
-
-static int register_devlink_port(struct mlx5_core_dev *dev,
- struct mlx5e_rep_priv *rpriv)
-{
- struct devlink *devlink = priv_to_devlink(dev);
- struct mlx5_eswitch_rep *rep = rpriv->rep;
- struct netdev_phys_item_id ppid = {};
- unsigned int dl_port_index = 0;
-
- if (!is_devlink_port_supported(dev, rpriv))
- return 0;
-
- mlx5e_rep_get_port_parent_id(rpriv->netdev, &ppid);
-
- if (rep->vport == MLX5_VPORT_UPLINK) {
- devlink_port_attrs_set(&rpriv->dl_port,
- DEVLINK_PORT_FLAVOUR_PHYSICAL,
- PCI_FUNC(dev->pdev->devfn), false, 0,
- &ppid.id[0], ppid.id_len);
- dl_port_index = vport_to_devlink_port_index(dev, rep->vport);
- } else if (rep->vport == MLX5_VPORT_PF) {
- devlink_port_attrs_pci_pf_set(&rpriv->dl_port,
- &ppid.id[0], ppid.id_len,
- dev->pdev->devfn);
- dl_port_index = rep->vport;
- } else if (mlx5_eswitch_is_vf_vport(dev->priv.eswitch,
- rpriv->rep->vport)) {
- devlink_port_attrs_pci_vf_set(&rpriv->dl_port,
- &ppid.id[0], ppid.id_len,
- dev->pdev->devfn,
- rep->vport - 1);
- dl_port_index = vport_to_devlink_port_index(dev, rep->vport);
- }
-
- return devlink_port_register(devlink, &rpriv->dl_port, dl_port_index);
-}
-
-static void unregister_devlink_port(struct mlx5_core_dev *dev,
- struct mlx5e_rep_priv *rpriv)
-{
- if (is_devlink_port_supported(dev, rpriv))
- devlink_port_unregister(&rpriv->dl_port);
-}
-
/* e-Switch vport representors */
static int
mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
@@ -1857,6 +1789,7 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
const struct mlx5e_profile *profile;
struct mlx5e_rep_priv *rpriv;
struct net_device *netdev;
+ struct mlx5_vport *vport;
int nch, err;
rpriv = kzalloc(sizeof(*rpriv), GFP_KERNEL);
@@ -1901,7 +1834,8 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
goto err_detach_netdev;
}
- err = register_devlink_port(dev, rpriv);
+ vport = mlx5_eswitch_get_vport(dev->priv.eswitch, rep->vport);
+ err = mlx5_devlink_port_register(dev, vport);
if (err) {
esw_warn(dev, "Failed to register devlink port %d\n",
rep->vport);
@@ -1915,12 +1849,12 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
goto err_devlink_cleanup;
}
- if (is_devlink_port_supported(dev, rpriv))
- devlink_port_type_eth_set(&rpriv->dl_port, netdev);
+ if (mlx5_devlink_port_supported(dev, vport))
+ devlink_port_type_eth_set(&vport->dl_port, netdev);
return 0;
err_devlink_cleanup:
- unregister_devlink_port(dev, rpriv);
+ mlx5_devlink_port_unregister(dev, vport);
err_neigh_cleanup:
mlx5e_rep_neigh_cleanup(rpriv);
@@ -1946,11 +1880,13 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *dev = priv->mdev;
void *ppriv = priv->ppriv;
+ struct mlx5_vport *vport;
- if (is_devlink_port_supported(dev, rpriv))
- devlink_port_type_clear(&rpriv->dl_port);
+ vport = mlx5_eswitch_get_vport(dev->priv.eswitch, rep->vport);
+ if (mlx5_devlink_port_supported(dev, vport))
+ devlink_port_type_clear(&vport->dl_port);
unregister_netdev(netdev);
- unregister_devlink_port(dev, rpriv);
+ mlx5_devlink_port_unregister(dev, vport);
mlx5e_rep_neigh_cleanup(rpriv);
mlx5e_detach_netdev(priv);
if (rep->vport == MLX5_VPORT_UPLINK)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
index 31f83c8adcc9..bc15801ebefd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
@@ -39,6 +39,7 @@
#include "eswitch.h"
#include "en.h"
#include "lib/port_tun.h"
+#include "devlink.h"
#ifdef CONFIG_MLX5_ESWITCH
struct mlx5e_neigh_update_table {
@@ -90,7 +91,6 @@ struct mlx5e_rep_priv {
struct list_head vport_sqs_list;
struct mlx5_rep_uplink_priv uplink_priv; /* valid for uplink rep */
struct rtnl_link_stats64 prev_vf_vport_stats;
- struct devlink_port dl_port;
};
static inline
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 920d8f529fb9..e27d372e1c07 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -138,6 +138,7 @@ struct mlx5_vport {
bool enabled;
enum mlx5_eswitch_vport_event enabled_events;
+ struct devlink_port dl_port;
};
enum offloads_fdb_flags {
--
2.19.2
^ permalink raw reply related [flat|nested] 132+ messages in thread
* [PATCH net-next 02/19] net/mlx5: E-Switch, Add SF vport, vport-rep support
2019-11-07 16:08 ` [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port Parav Pandit
@ 2019-11-07 16:08 ` Parav Pandit
2019-11-07 16:08 ` [PATCH net-next 03/19] net/mlx5: Introduce SF table framework Parav Pandit
` (17 subsequent siblings)
18 siblings, 0 replies; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:08 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Vu Pham,
Parav Pandit
From: Vu Pham <vuhuong@mellanox.com>
mlx5 Sub Function(SF) shares large amount functionalities and
capabilities as that of its parent PCI device.
Similar to SR-IOV VFs, each SF at present has one eswitch vport.
Assign a dedicated placeholder for SFs vports and their representors.
They are placed after VFs vports and before ECPF vports as below:
[PF,VF0,...,VFn,SF0,...SFm,ECPF,UPLINK].
Change functions to map SF's vport numbers to indices when
accessing the vports or representors arrays, and vice versa.
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Vu Pham <vuhuong@mellanox.com>
Signed-off-by: Parav Pandit <parav@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/Kconfig | 11 +++
.../net/ethernet/mellanox/mlx5/core/eswitch.c | 6 ++
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 70 +++++++++++++++++++
.../mellanox/mlx5/core/eswitch_offloads.c | 19 ++++-
.../ethernet/mellanox/mlx5/core/meddev/sf.h | 17 +++++
.../net/ethernet/mellanox/mlx5/core/vport.c | 4 +-
6 files changed, 123 insertions(+), 4 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
index a1f20b205299..a088b5fd339d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
@@ -161,3 +161,14 @@ config MLX5_SW_STEERING
default y
help
Build support for software-managed steering in the NIC.
+
+config MLX5_MDEV
+ bool "Mellanox Technologies Mediated device support"
+ depends on MLX5_CORE
+ depends on VFIO_MDEV
+ depends on MLX5_ESWITCH
+ default n
+ help
+ Build support for mediated devices. Mediated devices allow creating
+ multiple virtual ports, netdev and/or rdma device(s) on
+ single PCI function.
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 7baade9e62b7..87273be44dae 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1883,9 +1883,15 @@ const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
{
int outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out);
u32 in[MLX5_ST_SZ_DW(query_esw_functions_in)] = {};
+ u16 max_sfs;
u32 *out;
int err;
+ max_sfs = mlx5_eswitch_max_sfs(dev);
+ /* Device interface is array of 64-bits */
+ if (max_sfs)
+ outlen += DIV_ROUND_UP(max_sfs, BITS_PER_TYPE(__be64)) * sizeof(__be64);
+
out = kvzalloc(outlen, GFP_KERNEL);
if (!out)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index e27d372e1c07..21592ef6d05d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -42,6 +42,8 @@
#include <linux/mlx5/vport.h>
#include <linux/mlx5/fs.h>
#include "lib/mpfs.h"
+#include "mlx5_core.h"
+#include "meddev/sf.h"
#ifdef CONFIG_MLX5_ESWITCH
@@ -506,6 +508,44 @@ static inline int mlx5_eswitch_ecpf_idx(struct mlx5_eswitch *esw)
return esw->total_vports - 2;
}
+/* SF vport numbers in device range from the esw_sf_base_id and log_max_esw_sf.
+ * Below helpers perform conversion from SF vport index in software array
+ * to vport number and vice versa.
+ */
+static inline u16 mlx5_eswitch_sf_vport_base_id(const struct mlx5_core_dev *dev)
+{
+ return MLX5_CAP_ESW(dev, esw_sf_base_id);
+}
+
+static inline u16 mlx5_eswitch_max_sfs(const struct mlx5_core_dev *dev)
+{
+ return mlx5_core_is_sf_supported(dev) ?
+ 1 << MLX5_CAP_ESW(dev, log_max_esw_sf) : 0;
+}
+
+static inline int
+mlx5_eswitch_sf_index(const struct mlx5_eswitch *esw, u16 vport_num)
+{
+ return vport_num - mlx5_eswitch_sf_vport_base_id(esw->dev) +
+ MLX5_VPORT_PF_PLACEHOLDER + mlx5_core_max_vfs(esw->dev);
+}
+
+static inline u16
+mlx5_eswitch_sf_vport_num(const struct mlx5_eswitch *esw, int idx)
+{
+ return mlx5_eswitch_sf_vport_base_id(esw->dev) + idx -
+ (MLX5_VPORT_PF_PLACEHOLDER + mlx5_core_max_vfs(esw->dev));
+}
+
+static inline bool
+mlx5_eswitch_is_sf_vport(const struct mlx5_eswitch *esw, u16 vport_num)
+{
+ return mlx5_core_is_sf_supported(esw->dev) &&
+ vport_num >= mlx5_eswitch_sf_vport_base_id(esw->dev) &&
+ vport_num < (mlx5_eswitch_sf_vport_base_id(esw->dev) +
+ mlx5_eswitch_max_sfs(esw->dev));
+}
+
static inline int mlx5_eswitch_vport_num_to_index(struct mlx5_eswitch *esw,
u16 vport_num)
{
@@ -518,6 +558,10 @@ static inline int mlx5_eswitch_vport_num_to_index(struct mlx5_eswitch *esw,
if (vport_num == MLX5_VPORT_UPLINK)
return mlx5_eswitch_uplink_idx(esw);
+ if (mlx5_eswitch_is_sf_vport(esw, vport_num))
+ return mlx5_eswitch_sf_index(esw, vport_num);
+
+ /* PF and VF vports start from 0 to max_vfs */
return vport_num;
}
@@ -531,6 +575,12 @@ static inline u16 mlx5_eswitch_index_to_vport_num(struct mlx5_eswitch *esw,
if (index == mlx5_eswitch_uplink_idx(esw))
return MLX5_VPORT_UPLINK;
+ /* SF vports indices are after VFs and before ECPF */
+ if (mlx5_core_is_sf_supported(esw->dev) &&
+ index > mlx5_core_max_vfs(esw->dev))
+ return mlx5_eswitch_sf_vport_num(esw, index);
+
+ /* PF and VF vports start from 0 to max_vfs */
return index;
}
@@ -573,6 +623,21 @@ void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw);
(rep) = &(esw)->offloads.vport_reps[i], \
(i) <= (nvfs); (i)++)
+static inline int mlx5_eswitch_sf_start_idx(const struct mlx5_eswitch *esw)
+{
+ return MLX5_VPORT_PF_PLACEHOLDER + mlx5_core_max_vfs(esw->dev);
+}
+
+static inline int mlx5_eswitch_sf_end(const struct mlx5_eswitch *esw)
+{
+ return mlx5_eswitch_sf_start_idx(esw) + mlx5_eswitch_max_sfs(esw->dev);
+}
+
+#define mlx5_esw_for_each_sf_rep(esw, i, rep) \
+ for ((i) = mlx5_eswitch_sf_start_idx(esw); \
+ (rep) = &(esw)->offloads.vport_reps[(i)], \
+ (i) < mlx5_eswitch_sf_end(esw); (i++)) \
+
#define mlx5_esw_for_each_vf_rep_reverse(esw, i, rep, nvfs) \
for ((i) = (nvfs); \
(rep) = &(esw)->offloads.vport_reps[i], \
@@ -642,6 +707,11 @@ static inline void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, cons
#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1)
#define FDB_MAX_PRIO 1
+static inline u16 mlx5_eswitch_max_sfs(const struct mlx5_core_dev *dev)
+{
+ return 0;
+}
+
#endif /* CONFIG_MLX5_ESWITCH */
#endif /* __MLX5_ESWITCH_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 9924f06f0c2d..ff084499d681 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -1467,8 +1467,18 @@ static void esw_offloads_unload_vf_reps(struct mlx5_eswitch *esw, int nvports)
__unload_reps_vf_vport(esw, nvports, rep_type);
}
+static void __unload_reps_sf_vport(struct mlx5_eswitch *esw, u8 rep_type)
+{
+ struct mlx5_eswitch_rep *rep;
+ int i;
+
+ mlx5_esw_for_each_sf_rep(esw, i, rep)
+ __esw_offloads_unload_rep(esw, rep, rep_type);
+}
+
static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
{
+ __unload_reps_sf_vport(esw, rep_type);
__unload_reps_vf_vport(esw, esw->esw_funcs.num_vfs, rep_type);
/* Special vports must be the last to unload. */
@@ -1928,7 +1938,8 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
}
if (MLX5_CAP_GEN(esw->dev, prio_tag_required) &&
- mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
+ (mlx5_eswitch_is_vf_vport(esw, vport->vport) ||
+ mlx5_eswitch_is_sf_vport(esw, vport->vport))) {
err = esw_vport_ingress_prio_tag_config(esw, vport);
if (err)
goto prio_tag_err;
@@ -2006,7 +2017,8 @@ esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw,
if (err)
return err;
- if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
+ if (mlx5_eswitch_is_vf_vport(esw, vport->vport) ||
+ mlx5_eswitch_is_sf_vport(esw, vport->vport)) {
err = esw_vport_egress_config(esw, vport);
if (err) {
esw_vport_del_ingress_acl_modify_metadata(esw, vport);
@@ -2061,7 +2073,8 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
if (mlx5_core_is_ecpf_esw_manager(esw->dev))
total_vports = esw->total_vports;
else
- total_vports = num_vfs + MLX5_SPECIAL_VPORTS(esw->dev);
+ total_vports = num_vfs + MLX5_SPECIAL_VPORTS(esw->dev) +
+ mlx5_eswitch_max_sfs(esw->dev);
memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb));
mutex_init(&esw->fdb_table.offloads.fdb_prio_lock);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
new file mode 100644
index 000000000000..0cd28506e339
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies */
+
+#ifndef __MLX5_SF_H__
+#define __MLX5_SF_H__
+
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/eswitch.h>
+
+static inline bool mlx5_core_is_sf_supported(const struct mlx5_core_dev *dev)
+{
+ return MLX5_ESWITCH_MANAGER(dev) &&
+ MLX5_CAP_GEN(dev, max_num_sf_partitions) &&
+ MLX5_CAP_GEN(dev, sf);
+}
+
+#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
index 30f7848a6f88..ffcaa04700bd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
@@ -36,6 +36,7 @@
#include <linux/mlx5/vport.h>
#include <linux/mlx5/eswitch.h>
#include "mlx5_core.h"
+#include "eswitch.h"
/* Mutex to hold while enabling or disabling RoCE */
static DEFINE_MUTEX(mlx5_roce_en_lock);
@@ -1178,6 +1179,7 @@ EXPORT_SYMBOL_GPL(mlx5_query_nic_system_image_guid);
*/
u16 mlx5_eswitch_get_total_vports(const struct mlx5_core_dev *dev)
{
- return MLX5_SPECIAL_VPORTS(dev) + mlx5_core_max_vfs(dev);
+ return MLX5_SPECIAL_VPORTS(dev) + mlx5_core_max_vfs(dev) +
+ mlx5_eswitch_max_sfs(dev);
}
EXPORT_SYMBOL(mlx5_eswitch_get_total_vports);
--
2.19.2
^ permalink raw reply related [flat|nested] 132+ messages in thread
* [PATCH net-next 03/19] net/mlx5: Introduce SF table framework
2019-11-07 16:08 ` [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port Parav Pandit
2019-11-07 16:08 ` [PATCH net-next 02/19] net/mlx5: E-Switch, Add SF vport, vport-rep support Parav Pandit
@ 2019-11-07 16:08 ` Parav Pandit
2019-11-07 16:08 ` [PATCH net-next 04/19] net/mlx5: Introduce SF life cycle APIs to allocate/free Parav Pandit
` (16 subsequent siblings)
18 siblings, 0 replies; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:08 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Vu Pham,
Parav Pandit
From: Vu Pham <vuhuong@mellanox.com>
Introduce a SF table for SF life cycle for a device which supports SF
capability.
This SF table framework is used in subsequent patches.
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Parav Pandit <parav@mellanox.com>
Signed-off-by: Vu Pham <vuhuong@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/Makefile | 4 ++
drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 2 +
.../net/ethernet/mellanox/mlx5/core/main.c | 5 ++
.../ethernet/mellanox/mlx5/core/meddev/sf.c | 62 +++++++++++++++++++
.../ethernet/mellanox/mlx5/core/meddev/sf.h | 15 +++++
5 files changed, 88 insertions(+)
create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index a6f390fdb971..b13a0c91662b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -74,3 +74,7 @@ mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o
steering/dr_ste.o steering/dr_send.o \
steering/dr_cmd.o steering/dr_fw.o \
steering/dr_action.o steering/fs_dr.o
+#
+# Mdev basic
+#
+mlx5_core-$(CONFIG_MLX5_MDEV) += meddev/sf.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index ea934cd02448..e9a326939f5e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -448,6 +448,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_ALLOC_MEMIC:
case MLX5_CMD_OP_MODIFY_XRQ:
case MLX5_CMD_OP_RELEASE_XRQ_ERROR:
+ case MLX5_CMD_OP_QUERY_SF_PARTITION:
*status = MLX5_DRIVER_STATUS_ABORTED;
*synd = MLX5_DRIVER_SYND;
return -EIO;
@@ -474,6 +475,7 @@ const char *mlx5_command_str(int command)
MLX5_COMMAND_STR_CASE(QUERY_ISSI);
MLX5_COMMAND_STR_CASE(SET_ISSI);
MLX5_COMMAND_STR_CASE(SET_DRIVER_VERSION);
+ MLX5_COMMAND_STR_CASE(QUERY_SF_PARTITION);
MLX5_COMMAND_STR_CASE(CREATE_MKEY);
MLX5_COMMAND_STR_CASE(QUERY_MKEY);
MLX5_COMMAND_STR_CASE(DESTROY_MKEY);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index c9a091d3226c..174ade250f62 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -577,6 +577,11 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
num_vhca_ports,
MLX5_CAP_GEN_MAX(dev, num_vhca_ports));
+#ifdef CONFIG_MLX5_MDEV
+ if (MLX5_CAP_GEN_MAX(dev, sf))
+ MLX5_SET(cmd_hca_cap, set_hca_cap, sf, 1);
+#endif
+
err = set_caps(dev, set_ctx, set_sz,
MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
new file mode 100644
index 000000000000..3324cc53efe3
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2018-19 Mellanox Technologies
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "sf.h"
+#include "mlx5_core.h"
+
+static int
+mlx5_cmd_query_sf_partitions(struct mlx5_core_dev *mdev, u32 *out, int outlen)
+{
+ u32 in[MLX5_ST_SZ_DW(query_sf_partitions_in)] = {};
+
+ /* Query sf partitions */
+ MLX5_SET(query_sf_partitions_in, in, opcode,
+ MLX5_CMD_OP_QUERY_SF_PARTITION);
+ return mlx5_cmd_exec(mdev, in, sizeof(in), out, outlen);
+}
+
+int mlx5_sf_table_init(struct mlx5_core_dev *dev,
+ struct mlx5_sf_table *sf_table)
+{
+ void *sf_parts;
+ int n_support;
+ int outlen;
+ u32 *out;
+ int err;
+
+ outlen = MLX5_ST_SZ_BYTES(query_sf_partitions_out) + MLX5_ST_SZ_BYTES(sf_partition);
+ out = kvzalloc(outlen, GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ mutex_init(&sf_table->lock);
+ /* SFs BAR is implemented in PCI BAR2 */
+ sf_table->base_address = pci_resource_start(dev->pdev, 2);
+
+ /* Query first partition */
+ err = mlx5_cmd_query_sf_partitions(dev, out, outlen);
+ if (err)
+ goto free_outmem;
+
+ n_support = MLX5_GET(query_sf_partitions_out, out, num_sf_partitions);
+ sf_parts = MLX5_ADDR_OF(query_sf_partitions_out, out, sf_partition);
+ sf_table->max_sfs = 1 << MLX5_GET(sf_partition, sf_parts, log_num_sf);
+ sf_table->log_sf_bar_size =
+ MLX5_GET(sf_partition, sf_parts, log_sf_bar_size);
+
+ mlx5_core_dbg(dev, "supported partitions(%d)\n", n_support);
+ mlx5_core_dbg(dev, "SF_part(0) log_num_sf(%d) log_sf_bar_size(%d)\n",
+ sf_table->max_sfs, sf_table->log_sf_bar_size);
+
+free_outmem:
+ kvfree(out);
+ return err;
+}
+
+void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev,
+ struct mlx5_sf_table *sf_table)
+{
+ mutex_destroy(&sf_table->lock);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
index 0cd28506e339..434c193a06d0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
@@ -7,6 +7,14 @@
#include <linux/mlx5/driver.h>
#include <linux/mlx5/eswitch.h>
+struct mlx5_sf_table {
+ phys_addr_t base_address;
+ /* Protects sfs life cycle and sf enable/disable flows */
+ struct mutex lock;
+ u16 max_sfs;
+ u16 log_sf_bar_size;
+};
+
static inline bool mlx5_core_is_sf_supported(const struct mlx5_core_dev *dev)
{
return MLX5_ESWITCH_MANAGER(dev) &&
@@ -14,4 +22,11 @@ static inline bool mlx5_core_is_sf_supported(const struct mlx5_core_dev *dev)
MLX5_CAP_GEN(dev, sf);
}
+#ifdef CONFIG_MLX5_MDEV
+int mlx5_sf_table_init(struct mlx5_core_dev *dev,
+ struct mlx5_sf_table *sf_table);
+void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev,
+ struct mlx5_sf_table *sf_table);
+#endif
+
#endif
--
2.19.2
^ permalink raw reply related [flat|nested] 132+ messages in thread
* [PATCH net-next 04/19] net/mlx5: Introduce SF life cycle APIs to allocate/free
2019-11-07 16:08 ` [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port Parav Pandit
2019-11-07 16:08 ` [PATCH net-next 02/19] net/mlx5: E-Switch, Add SF vport, vport-rep support Parav Pandit
2019-11-07 16:08 ` [PATCH net-next 03/19] net/mlx5: Introduce SF table framework Parav Pandit
@ 2019-11-07 16:08 ` Parav Pandit
2019-11-07 16:08 ` [PATCH net-next 05/19] net/mlx5: E-Switch, Enable/disable SF's vport during SF life cycle Parav Pandit
` (15 subsequent siblings)
18 siblings, 0 replies; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:08 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Parav Pandit,
Vu Pham
Introduce SF life cycle APIs to allocate, deallocate it at device
level.
Make use of low level device life cycle APIs and provide higher level
API for a usable SF creation/deletion.
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Parav Pandit <parav@mellanox.com>
Signed-off-by: Vu Pham <vuhuong@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 4 +
.../net/ethernet/mellanox/mlx5/core/main.c | 43 +++++--
.../ethernet/mellanox/mlx5/core/meddev/sf.c | 116 +++++++++++++++++-
.../ethernet/mellanox/mlx5/core/meddev/sf.h | 18 +++
.../ethernet/mellanox/mlx5/core/mlx5_core.h | 2 +
5 files changed, 172 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index e9a326939f5e..3f1a9a73b25f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -317,6 +317,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_DEALLOC_MEMIC:
case MLX5_CMD_OP_PAGE_FAULT_RESUME:
case MLX5_CMD_OP_QUERY_ESW_FUNCTIONS:
+ case MLX5_CMD_OP_DEALLOC_SF:
return MLX5_CMD_STAT_OK;
case MLX5_CMD_OP_QUERY_HCA_CAP:
@@ -449,6 +450,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_MODIFY_XRQ:
case MLX5_CMD_OP_RELEASE_XRQ_ERROR:
case MLX5_CMD_OP_QUERY_SF_PARTITION:
+ case MLX5_CMD_OP_ALLOC_SF:
*status = MLX5_DRIVER_STATUS_ABORTED;
*synd = MLX5_DRIVER_SYND;
return -EIO;
@@ -476,6 +478,8 @@ const char *mlx5_command_str(int command)
MLX5_COMMAND_STR_CASE(SET_ISSI);
MLX5_COMMAND_STR_CASE(SET_DRIVER_VERSION);
MLX5_COMMAND_STR_CASE(QUERY_SF_PARTITION);
+ MLX5_COMMAND_STR_CASE(ALLOC_SF);
+ MLX5_COMMAND_STR_CASE(DEALLOC_SF);
MLX5_COMMAND_STR_CASE(CREATE_MKEY);
MLX5_COMMAND_STR_CASE(QUERY_MKEY);
MLX5_COMMAND_STR_CASE(DESTROY_MKEY);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 174ade250f62..092e2c90caf1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -644,30 +644,53 @@ static int mlx5_core_set_hca_defaults(struct mlx5_core_dev *dev)
return ret;
}
-int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id)
+static int enable_hca(struct mlx5_core_dev *dev, u16 func_id, bool ecpu)
{
- u32 out[MLX5_ST_SZ_DW(enable_hca_out)] = {0};
- u32 in[MLX5_ST_SZ_DW(enable_hca_in)] = {0};
+ u32 out[MLX5_ST_SZ_DW(enable_hca_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(enable_hca_in)] = {};
MLX5_SET(enable_hca_in, in, opcode, MLX5_CMD_OP_ENABLE_HCA);
MLX5_SET(enable_hca_in, in, function_id, func_id);
- MLX5_SET(enable_hca_in, in, embedded_cpu_function,
- dev->caps.embedded_cpu);
+ MLX5_SET(enable_hca_in, in, embedded_cpu_function, ecpu);
return mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
}
-int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id)
+int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id)
{
- u32 out[MLX5_ST_SZ_DW(disable_hca_out)] = {0};
- u32 in[MLX5_ST_SZ_DW(disable_hca_in)] = {0};
+ return enable_hca(dev, func_id, dev->caps.embedded_cpu);
+}
+
+int mlx5_core_enable_sf_hca(struct mlx5_core_dev *dev, u16 sf_func_id)
+{
+ /* When enabling SF, it doesn't matter if is enabled on ECPF or PF,
+ * embedded_cpu bit must be cleared as expected by device firmware.
+ * SF function ids are split between ECPF And PF. A given SF is for
+ * ECPF or for PF is decided by SF's function id by the firmware.
+ */
+ return enable_hca(dev, sf_func_id, 0);
+}
+
+static int disable_hca(struct mlx5_core_dev *dev, u16 func_id, bool ecpu)
+{
+ u32 out[MLX5_ST_SZ_DW(disable_hca_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(disable_hca_in)] = {};
MLX5_SET(disable_hca_in, in, opcode, MLX5_CMD_OP_DISABLE_HCA);
MLX5_SET(disable_hca_in, in, function_id, func_id);
- MLX5_SET(enable_hca_in, in, embedded_cpu_function,
- dev->caps.embedded_cpu);
+ MLX5_SET(enable_hca_in, in, embedded_cpu_function, ecpu);
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
+int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id)
+{
+ return disable_hca(dev, func_id, dev->caps.embedded_cpu);
+}
+
+int mlx5_core_disable_sf_hca(struct mlx5_core_dev *dev, u16 sf_func_id)
+{
+ return disable_hca(dev, sf_func_id, 0);
+}
+
u64 mlx5_read_internal_timer(struct mlx5_core_dev *dev,
struct ptp_system_timestamp *sts)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
index 3324cc53efe3..d57109a9c53b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
@@ -3,6 +3,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/io-mapping.h>
+#include <linux/bitmap.h>
#include "sf.h"
#include "mlx5_core.h"
@@ -31,7 +33,6 @@ int mlx5_sf_table_init(struct mlx5_core_dev *dev,
if (!out)
return -ENOMEM;
- mutex_init(&sf_table->lock);
/* SFs BAR is implemented in PCI BAR2 */
sf_table->base_address = pci_resource_start(dev->pdev, 2);
@@ -46,6 +47,13 @@ int mlx5_sf_table_init(struct mlx5_core_dev *dev,
sf_table->log_sf_bar_size =
MLX5_GET(sf_partition, sf_parts, log_sf_bar_size);
+ sf_table->sf_id_bitmap = bitmap_zalloc(sf_table->max_sfs, GFP_KERNEL);
+ if (!sf_table->sf_id_bitmap) {
+ err = -ENOMEM;
+ goto free_outmem;
+ }
+ mutex_init(&sf_table->lock);
+
mlx5_core_dbg(dev, "supported partitions(%d)\n", n_support);
mlx5_core_dbg(dev, "SF_part(0) log_num_sf(%d) log_sf_bar_size(%d)\n",
sf_table->max_sfs, sf_table->log_sf_bar_size);
@@ -59,4 +67,110 @@ void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev,
struct mlx5_sf_table *sf_table)
{
mutex_destroy(&sf_table->lock);
+ bitmap_free(sf_table->sf_id_bitmap);
+}
+
+static int mlx5_cmd_alloc_sf(struct mlx5_core_dev *mdev, u16 function_id)
+{
+ u32 out[MLX5_ST_SZ_DW(alloc_sf_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(alloc_sf_in)] = {};
+
+ MLX5_SET(alloc_sf_in, in, opcode, MLX5_CMD_OP_ALLOC_SF);
+ MLX5_SET(alloc_sf_in, in, function_id, function_id);
+
+ return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+}
+
+static int mlx5_cmd_dealloc_sf(struct mlx5_core_dev *mdev, u16 function_id)
+{
+ u32 out[MLX5_ST_SZ_DW(dealloc_sf_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(dealloc_sf_in)] = {};
+
+ MLX5_SET(dealloc_sf_in, in, opcode, MLX5_CMD_OP_DEALLOC_SF);
+ MLX5_SET(dealloc_sf_in, in, function_id, function_id);
+
+ return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+}
+
+static int alloc_sf_id(struct mlx5_sf_table *sf_table, u16 *sf_id)
+{
+ int ret = 0;
+ u16 idx;
+
+ mutex_lock(&sf_table->lock);
+ idx = find_first_zero_bit(sf_table->sf_id_bitmap, sf_table->max_sfs);
+ if (idx == sf_table->max_sfs) {
+ ret = -ENOSPC;
+ goto done;
+ }
+ bitmap_set(sf_table->sf_id_bitmap, idx, 1);
+ *sf_id = idx;
+done:
+ mutex_unlock(&sf_table->lock);
+ return ret;
+}
+
+static void free_sf_id(struct mlx5_sf_table *sf_table, u16 sf_id)
+{
+ mutex_lock(&sf_table->lock);
+ bitmap_clear(sf_table->sf_id_bitmap, sf_id, 1);
+ mutex_unlock(&sf_table->lock);
+}
+
+static u16 mlx5_sf_hw_id(const struct mlx5_core_dev *coredev, u16 sf_id)
+{
+ return mlx5_sf_base_id(coredev) + sf_id;
+}
+
+/* Perform SF allocation using parent device BAR. */
+struct mlx5_sf *
+mlx5_sf_alloc(struct mlx5_core_dev *coredev, struct mlx5_sf_table *sf_table,
+ struct device *dev)
+{
+ struct mlx5_sf *sf;
+ u16 hw_function_id;
+ u16 sf_id;
+ int ret;
+
+ sf = kzalloc(sizeof(*sf), GFP_KERNEL);
+ if (!sf)
+ return ERR_PTR(-ENOMEM);
+
+ ret = alloc_sf_id(sf_table, &sf_id);
+ if (ret)
+ goto id_err;
+
+ hw_function_id = mlx5_sf_hw_id(coredev, sf_id);
+ ret = mlx5_cmd_alloc_sf(coredev, hw_function_id);
+ if (ret)
+ goto alloc_sf_err;
+
+ ret = mlx5_core_enable_sf_hca(coredev, hw_function_id);
+ if (ret)
+ goto enable_err;
+
+ sf->idx = sf_id;
+ sf->base_addr = sf_table->base_address +
+ (sf->idx << (sf_table->log_sf_bar_size + 12));
+ return sf;
+
+enable_err:
+ mlx5_cmd_dealloc_sf(coredev, hw_function_id);
+alloc_sf_err:
+ free_sf_id(sf_table, sf_id);
+id_err:
+ kfree(sf);
+ return ERR_PTR(ret);
+}
+
+void mlx5_sf_free(struct mlx5_core_dev *coredev, struct mlx5_sf_table *sf_table,
+ struct mlx5_sf *sf)
+{
+ u16 hw_function_id;
+
+ hw_function_id = mlx5_sf_hw_id(coredev, sf->idx);
+ mlx5_core_disable_sf_hca(coredev, hw_function_id);
+ mlx5_cmd_dealloc_sf(coredev, hw_function_id);
+ free_sf_id(sf_table, sf->idx);
+ kfree(sf);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
index 434c193a06d0..1e1ba388504c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
@@ -6,11 +6,18 @@
#include <linux/mlx5/driver.h>
#include <linux/mlx5/eswitch.h>
+#include <linux/idr.h>
+
+struct mlx5_sf {
+ phys_addr_t base_addr;
+ u16 idx; /* Index allocated by the SF table bitmap */
+};
struct mlx5_sf_table {
phys_addr_t base_address;
/* Protects sfs life cycle and sf enable/disable flows */
struct mutex lock;
+ unsigned long *sf_id_bitmap;
u16 max_sfs;
u16 log_sf_bar_size;
};
@@ -22,11 +29,22 @@ static inline bool mlx5_core_is_sf_supported(const struct mlx5_core_dev *dev)
MLX5_CAP_GEN(dev, sf);
}
+static inline u16 mlx5_sf_base_id(const struct mlx5_core_dev *dev)
+{
+ return MLX5_CAP_GEN(dev, sf_base_id);
+}
+
#ifdef CONFIG_MLX5_MDEV
int mlx5_sf_table_init(struct mlx5_core_dev *dev,
struct mlx5_sf_table *sf_table);
void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev,
struct mlx5_sf_table *sf_table);
+
+struct mlx5_sf *
+mlx5_sf_alloc(struct mlx5_core_dev *coredev, struct mlx5_sf_table *sf_table,
+ struct device *dev);
+void mlx5_sf_free(struct mlx5_core_dev *coredev, struct mlx5_sf_table *sf_table,
+ struct mlx5_sf *sf);
#endif
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index b100489dc85c..4e6bdae3ebfa 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -133,6 +133,8 @@ void mlx5_sriov_detach(struct mlx5_core_dev *dev);
int mlx5_core_sriov_configure(struct pci_dev *dev, int num_vfs);
int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id);
int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id);
+int mlx5_core_enable_sf_hca(struct mlx5_core_dev *dev, u16 sf_func_id);
+int mlx5_core_disable_sf_hca(struct mlx5_core_dev *dev, u16 sf_func_id);
int mlx5_create_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
void *context, u32 *element_id);
int mlx5_modify_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
--
2.19.2
^ permalink raw reply related [flat|nested] 132+ messages in thread
* [PATCH net-next 05/19] net/mlx5: E-Switch, Enable/disable SF's vport during SF life cycle
2019-11-07 16:08 ` [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port Parav Pandit
` (2 preceding siblings ...)
2019-11-07 16:08 ` [PATCH net-next 04/19] net/mlx5: Introduce SF life cycle APIs to allocate/free Parav Pandit
@ 2019-11-07 16:08 ` Parav Pandit
2019-11-07 16:08 ` [PATCH net-next 06/19] net/mlx5: Add support for mediated devices in switchdev mode Parav Pandit
` (14 subsequent siblings)
18 siblings, 0 replies; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:08 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Vu Pham,
Parav Pandit
From: Vu Pham <vuhuong@mellanox.com>
Enable/disable SF vport and its representors during SF
allocation/free sequence respectively.
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Vu Pham <vuhuong@mellanox.com>
Signed-off-by: Parav Pandit <parav@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/eswitch.c | 16 +--
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 7 ++
.../mellanox/mlx5/core/eswitch_offloads.c | 111 ++++++++++++++++++
.../ethernet/mellanox/mlx5/core/meddev/sf.c | 8 ++
4 files changed, 134 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 87273be44dae..1c763a5c955c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1532,9 +1532,9 @@ static void esw_destroy_tsar(struct mlx5_eswitch *esw)
esw->qos.enabled = false;
}
-static int esw_vport_enable_qos(struct mlx5_eswitch *esw,
- struct mlx5_vport *vport,
- u32 initial_max_rate, u32 initial_bw_share)
+int mlx5_eswitch_vport_enable_qos(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport,
+ u32 initial_max_rate, u32 initial_bw_share)
{
u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
struct mlx5_core_dev *dev = esw->dev;
@@ -1573,8 +1573,8 @@ static int esw_vport_enable_qos(struct mlx5_eswitch *esw,
return 0;
}
-static void esw_vport_disable_qos(struct mlx5_eswitch *esw,
- struct mlx5_vport *vport)
+void mlx5_eswitch_vport_disable_qos(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport)
{
int err;
@@ -1795,8 +1795,8 @@ static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
goto done;
/* Attach vport to the eswitch rate limiter */
- if (esw_vport_enable_qos(esw, vport, vport->info.max_rate,
- vport->qos.bw_share))
+ if (mlx5_eswitch_vport_enable_qos(esw, vport, vport->info.max_rate,
+ vport->qos.bw_share))
esw_warn(esw->dev, "Failed to attach vport %d to eswitch rate limiter", vport_num);
/* Sync with current vport context */
@@ -1840,7 +1840,7 @@ static void esw_disable_vport(struct mlx5_eswitch *esw,
*/
esw_vport_change_handle_locked(vport);
vport->enabled_events = 0;
- esw_vport_disable_qos(esw, vport);
+ mlx5_eswitch_vport_disable_qos(esw, vport);
if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
esw->mode == MLX5_ESWITCH_LEGACY)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 21592ef6d05d..6c2ea3bb39cb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -298,6 +298,13 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
u16 vport,
struct ifla_vf_stats *vf_stats);
+int mlx5_eswitch_vport_enable_qos(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport,
+ u32 initial_max_rate, u32 initial_bw_share);
+void mlx5_eswitch_vport_disable_qos(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport);
+int mlx5_eswitch_setup_sf_vport(struct mlx5_eswitch *esw, u16 vport_num);
+void mlx5_eswitch_cleanup_sf_vport(struct mlx5_eswitch *esw, u16 vport_num);
void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule);
int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev *dev, u16 vport,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index ff084499d681..a6906bff37a3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -1624,6 +1624,117 @@ static int esw_offloads_load_all_reps(struct mlx5_eswitch *esw)
return err;
}
+static int esw_offloads_load_vport_reps(struct mlx5_eswitch *esw, u16 vport_num)
+{
+ struct mlx5_eswitch_rep *rep;
+ u8 rep_type;
+ int err;
+
+ rep = mlx5_eswitch_get_rep(esw, vport_num);
+ for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
+ err = __esw_offloads_load_rep(esw, rep, rep_type);
+ if (err) {
+ esw_warn(esw->dev, "Load vport(%d) rep type(%d) err!\n",
+ vport_num, rep_type);
+ goto err_reps;
+ }
+ }
+
+ return 0;
+
+err_reps:
+ while (rep_type-- > 0)
+ __esw_offloads_unload_rep(esw, rep, rep_type);
+ return err;
+}
+
+static void
+esw_offloads_unload_vport_reps(struct mlx5_eswitch *esw, u16 vport_num)
+{
+ struct mlx5_eswitch_rep *rep;
+ u8 rep_type = NUM_REP_TYPES;
+
+ rep = mlx5_eswitch_get_rep(esw, vport_num);
+ while (rep_type-- > 0)
+ __esw_offloads_unload_rep(esw, rep, rep_type);
+}
+
+static int
+esw_enable_sf_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+{
+ int ret;
+
+ ret = esw_vport_create_offloads_acl_tables(esw, vport);
+ if (ret)
+ return ret;
+
+ mutex_lock(&esw->state_lock);
+
+ mlx5_modify_nic_vport_mac_address(esw->dev, vport->vport, vport->info.mac);
+ mlx5_modify_nic_vport_node_guid(esw->dev, vport->vport,
+ vport->info.node_guid);
+
+ /* Attach vport to the eswitch rate limiter */
+ ret = mlx5_eswitch_vport_enable_qos(esw, vport, vport->info.max_rate,
+ vport->qos.bw_share);
+ if (ret)
+ goto qos_err;
+
+ vport->enabled = true;
+ esw_debug(esw->dev, "Enabled SF vport(0x%x)\n", vport->vport);
+
+ mutex_unlock(&esw->state_lock);
+ return 0;
+
+qos_err:
+ mutex_unlock(&esw->state_lock);
+ esw_vport_destroy_offloads_acl_tables(esw, vport);
+ return ret;
+}
+
+static void
+esw_disable_sf_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+{
+ mutex_lock(&esw->state_lock);
+
+ esw_debug(esw->dev, "Disabling vport(0x%x)\n", vport->vport);
+ vport->enabled = false;
+ mlx5_eswitch_vport_disable_qos(esw, vport);
+
+ mutex_unlock(&esw->state_lock);
+
+ esw_vport_destroy_offloads_acl_tables(esw, vport);
+}
+
+int mlx5_eswitch_setup_sf_vport(struct mlx5_eswitch *esw, u16 vport_num)
+{
+ struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
+ int ret;
+
+ if (IS_ERR(vport))
+ return PTR_ERR(vport);
+
+ ret = esw_enable_sf_vport(esw, vport);
+ if (ret)
+ return ret;
+
+ ret = esw_offloads_load_vport_reps(esw, vport_num);
+ if (ret)
+ esw_disable_sf_vport(esw, vport);
+ return ret;
+}
+
+void mlx5_eswitch_cleanup_sf_vport(struct mlx5_eswitch *esw, u16 vport_num)
+{
+ struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
+
+ if (IS_ERR(vport))
+ return;
+
+ esw_offloads_unload_vport_reps(esw, vport_num);
+ esw_disable_sf_vport(esw, vport);
+}
+
#define ESW_OFFLOADS_DEVCOM_PAIR (0)
#define ESW_OFFLOADS_DEVCOM_UNPAIR (1)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
index d57109a9c53b..fb4ba7be0051 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
@@ -7,6 +7,7 @@
#include <linux/bitmap.h>
#include "sf.h"
#include "mlx5_core.h"
+#include "eswitch.h"
static int
mlx5_cmd_query_sf_partitions(struct mlx5_core_dev *mdev, u32 *out, int outlen)
@@ -149,11 +150,17 @@ mlx5_sf_alloc(struct mlx5_core_dev *coredev, struct mlx5_sf_table *sf_table,
if (ret)
goto enable_err;
+ ret = mlx5_eswitch_setup_sf_vport(coredev->priv.eswitch, hw_function_id);
+ if (ret)
+ goto vport_err;
+
sf->idx = sf_id;
sf->base_addr = sf_table->base_address +
(sf->idx << (sf_table->log_sf_bar_size + 12));
return sf;
+vport_err:
+ mlx5_core_disable_sf_hca(coredev, hw_function_id);
enable_err:
mlx5_cmd_dealloc_sf(coredev, hw_function_id);
alloc_sf_err:
@@ -169,6 +176,7 @@ void mlx5_sf_free(struct mlx5_core_dev *coredev, struct mlx5_sf_table *sf_table,
u16 hw_function_id;
hw_function_id = mlx5_sf_hw_id(coredev, sf->idx);
+ mlx5_eswitch_cleanup_sf_vport(coredev->priv.eswitch, hw_function_id);
mlx5_core_disable_sf_hca(coredev, hw_function_id);
mlx5_cmd_dealloc_sf(coredev, hw_function_id);
free_sf_id(sf_table, sf->idx);
--
2.19.2
^ permalink raw reply related [flat|nested] 132+ messages in thread
* [PATCH net-next 06/19] net/mlx5: Add support for mediated devices in switchdev mode
2019-11-07 16:08 ` [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port Parav Pandit
` (3 preceding siblings ...)
2019-11-07 16:08 ` [PATCH net-next 05/19] net/mlx5: E-Switch, Enable/disable SF's vport during SF life cycle Parav Pandit
@ 2019-11-07 16:08 ` Parav Pandit
2019-11-08 10:32 ` Jiri Pirko
2019-11-07 16:08 ` [PATCH net-next 07/19] vfio/mdev: Introduce sha1 based mdev alias Parav Pandit
` (13 subsequent siblings)
18 siblings, 1 reply; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:08 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Vu Pham,
Parav Pandit
From: Vu Pham <vuhuong@mellanox.com>
Implement mdev hooks to create mediated devices using mdev driver.
Actual mlx5_core driver in the host is expected to bind to these devices
using standard device driver model.
Mdev devices are supported only when eswitch mode is OFFLOADS mode.
Mdev devices are created using sysfs file as below example.
$ uuidgen
49d0e9ac-61b8-4c91-957e-6f6dbc42557d
$ echo 49d0e9ac-61b8-4c91-957e-6f6dbc42557d > \
/sys/bus/pci/devices/0000:05:00.0/mdev_supported_types/mlx5_core-local/create
$ echo 49d0e9ac-61b8-4c91-957e-6f6dbc42557d > \
/sys/bus/mdev/drivers/vfio_mdev/unbind
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Parav Pandit <parav@mellanox.com>
Signed-off-by: Vu Pham <vuhuong@mellanox.com>
---
.../net/ethernet/mellanox/mlx5/core/Makefile | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/dev.c | 17 ++
.../net/ethernet/mellanox/mlx5/core/eswitch.c | 2 +
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 5 +
.../mellanox/mlx5/core/eswitch_offloads.c | 14 ++
.../ethernet/mellanox/mlx5/core/meddev/mdev.c | 203 ++++++++++++++++++
.../ethernet/mellanox/mlx5/core/meddev/sf.c | 22 ++
.../ethernet/mellanox/mlx5/core/meddev/sf.h | 18 ++
.../ethernet/mellanox/mlx5/core/mlx5_core.h | 32 +++
9 files changed, 314 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/meddev/mdev.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index b13a0c91662b..34c2c39cc0c4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -77,4 +77,4 @@ mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o
#
# Mdev basic
#
-mlx5_core-$(CONFIG_MLX5_MDEV) += meddev/sf.o
+mlx5_core-$(CONFIG_MLX5_MDEV) += meddev/sf.o meddev/mdev.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
index 50862275544e..2c710fb252f0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
@@ -334,6 +334,23 @@ struct mlx5_core_dev *mlx5_get_next_phys_dev(struct mlx5_core_dev *dev)
return res;
}
+struct mlx5_core_dev *mlx5_get_core_dev(const struct device *dev)
+{
+ struct mlx5_core_dev *found = NULL;
+ struct mlx5_core_dev *tmp_dev;
+ struct mlx5_priv *priv;
+
+ mutex_lock(&mlx5_intf_mutex);
+ list_for_each_entry(priv, &mlx5_dev_list, dev_list) {
+ tmp_dev = container_of(priv, struct mlx5_core_dev, priv);
+ if (tmp_dev->device == dev) {
+ found = tmp_dev;
+ break;
+ }
+ }
+ mutex_unlock(&mlx5_intf_mutex);
+ return found;
+}
void mlx5_dev_list_lock(void)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 1c763a5c955c..3cd28dccee12 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -2153,6 +2153,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
dev->priv.eswitch = esw;
+ mlx5_meddev_init(esw);
return 0;
abort:
if (esw->work_queue)
@@ -2170,6 +2171,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
esw_info(esw->dev, "cleanup\n");
+ mlx5_meddev_cleanup(esw);
esw->dev->priv.eswitch = NULL;
destroy_workqueue(esw->work_queue);
esw_offloads_cleanup_reps(esw);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 6c2ea3bb39cb..ca7bf362a192 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -224,6 +224,8 @@ enum {
MLX5_ESWITCH_VPORT_MATCH_METADATA = BIT(0),
};
+struct mlx5_mdev_table;
+
struct mlx5_eswitch {
struct mlx5_core_dev *dev;
struct mlx5_nb nb;
@@ -253,6 +255,9 @@ struct mlx5_eswitch {
u16 manager_vport;
u16 first_host_vport;
struct mlx5_esw_functions esw_funcs;
+#ifdef CONFIG_MLX5_MDEV
+ struct mlx5_mdev_table *mdev_table;
+#endif
};
void esw_offloads_disable(struct mlx5_eswitch *esw);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index a6906bff37a3..503cefac300b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -2325,8 +2325,15 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
esw_offloads_devcom_init(esw);
mutex_init(&esw->offloads.termtbl_mutex);
+ err = mlx5_meddev_register(esw);
+ if (err)
+ goto err_meddev;
return 0;
+err_meddev:
+ mutex_destroy(&esw->offloads.termtbl_mutex);
+ esw_offloads_devcom_cleanup(esw);
+ esw_offloads_unload_all_reps(esw);
err_reps:
mlx5_eswitch_disable_pf_vf_vports(esw);
err_vports:
@@ -2341,9 +2348,15 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
static int esw_offloads_stop(struct mlx5_eswitch *esw,
struct netlink_ext_ack *extack)
{
+ bool can_cleanup;
int err, err1;
+ can_cleanup = mlx5_meddev_can_and_mark_cleanup(esw);
+ if (!can_cleanup)
+ return -EBUSY;
+
mlx5_eswitch_disable(esw, false);
+
err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
@@ -2359,6 +2372,7 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw,
void esw_offloads_disable(struct mlx5_eswitch *esw)
{
+ mlx5_meddev_unregister(esw);
esw_offloads_devcom_cleanup(esw);
esw_offloads_unload_all_reps(esw);
mlx5_eswitch_disable_pf_vf_vports(esw);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/meddev/mdev.c b/drivers/net/ethernet/mellanox/mlx5/core/meddev/mdev.c
new file mode 100644
index 000000000000..295932110eff
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/meddev/mdev.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Mellanox Technologies
+
+#include <net/devlink.h>
+#include <linux/mdev.h>
+#include <linux/refcount.h>
+
+#include "mlx5_core.h"
+#include "meddev/sf.h"
+#include "eswitch.h"
+
+struct mlx5_mdev_table {
+ struct mlx5_sf_table sf_table;
+ /* Synchronizes with mdev table cleanup check and mdev creation. */
+ struct srcu_struct offloads_srcu;
+ struct mlx5_core_dev *dev;
+};
+
+static ssize_t
+max_mdevs_show(struct kobject *kobj, struct device *dev, char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct mlx5_core_dev *coredev;
+ struct mlx5_mdev_table *table;
+ u16 max_sfs;
+
+ coredev = pci_get_drvdata(pdev);
+ table = coredev->priv.eswitch->mdev_table;
+ max_sfs = mlx5_core_max_sfs(coredev, &table->sf_table);
+
+ return sprintf(buf, "%d\n", max_sfs);
+}
+static MDEV_TYPE_ATTR_RO(max_mdevs);
+
+static ssize_t
+available_instances_show(struct kobject *kobj, struct device *dev, char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct mlx5_core_dev *coredev;
+ struct mlx5_mdev_table *table;
+ u16 free_sfs;
+
+ coredev = pci_get_drvdata(pdev);
+ table = coredev->priv.eswitch->mdev_table;
+ free_sfs = mlx5_get_free_sfs(coredev, &table->sf_table);
+ return sprintf(buf, "%d\n", free_sfs);
+}
+static MDEV_TYPE_ATTR_RO(available_instances);
+
+static struct attribute *mdev_dev_attrs[] = {
+ &mdev_type_attr_max_mdevs.attr,
+ &mdev_type_attr_available_instances.attr,
+ NULL,
+};
+
+static struct attribute_group mdev_mgmt_group = {
+ .name = "local",
+ .attrs = mdev_dev_attrs,
+};
+
+static struct attribute_group *mlx5_meddev_groups[] = {
+ &mdev_mgmt_group,
+ NULL,
+};
+
+static int mlx5_meddev_create(struct kobject *kobj, struct mdev_device *meddev)
+{
+ struct mlx5_core_dev *parent_coredev;
+ struct mlx5_mdev_table *table;
+ struct device *parent_dev;
+ struct mlx5_sf *sf;
+ int srcu_key;
+ int ret = 0;
+
+ parent_dev = mdev_parent_dev(meddev);
+ parent_coredev = mlx5_get_core_dev(parent_dev);
+ if (!parent_coredev)
+ return -ENODEV;
+
+ table = parent_coredev->priv.eswitch->mdev_table;
+ /* Publish that mdev creation is in progress, hence wait for it
+ * to complete, while changing eswitch mode.
+ */
+ srcu_key = srcu_read_lock(&table->offloads_srcu);
+ if (!srcu_dereference(table->dev, &table->offloads_srcu)) {
+ srcu_read_unlock(&table->offloads_srcu, srcu_key);
+ return -ENODEV;
+ }
+
+ sf = mlx5_sf_alloc(parent_coredev, &table->sf_table, mdev_dev(meddev));
+ if (IS_ERR(sf)) {
+ ret = PTR_ERR(sf);
+ goto sf_err;
+ }
+
+ mdev_set_drvdata(meddev, sf);
+sf_err:
+ srcu_read_unlock(&table->offloads_srcu, srcu_key);
+ return ret;
+}
+
+static int mlx5_meddev_remove(struct mdev_device *meddev)
+{
+ struct mlx5_sf *sf = mdev_get_drvdata(meddev);
+ struct mlx5_core_dev *parent_coredev;
+ struct mlx5_mdev_table *table;
+
+ parent_coredev = pci_get_drvdata(to_pci_dev(mdev_parent_dev(meddev)));
+ table = parent_coredev->priv.eswitch->mdev_table;
+ mlx5_sf_free(parent_coredev, &table->sf_table, sf);
+ return 0;
+}
+
+static const struct mdev_parent_ops mlx5_meddev_ops = {
+ .create = mlx5_meddev_create,
+ .remove = mlx5_meddev_remove,
+ .supported_type_groups = mlx5_meddev_groups,
+};
+
+void mlx5_meddev_init(struct mlx5_eswitch *esw)
+{
+ struct mlx5_mdev_table *table;
+ int ret;
+
+ if (!mlx5_core_is_sf_supported(esw->dev))
+ return;
+
+ table = kzalloc(sizeof(*table), GFP_KERNEL);
+ if (!table)
+ return;
+
+ ret = mlx5_sf_table_init(esw->dev, &table->sf_table);
+ if (ret) {
+ kfree(table);
+ return;
+ }
+
+ init_srcu_struct(&table->offloads_srcu);
+ esw->mdev_table = table;
+}
+
+void mlx5_meddev_cleanup(struct mlx5_eswitch *esw)
+{
+ struct mlx5_mdev_table *table;
+
+ if (!mlx5_core_is_sf_supported(esw->dev))
+ return;
+
+ table = esw->mdev_table;
+ cleanup_srcu_struct(&table->offloads_srcu);
+ mlx5_sf_table_cleanup(esw->dev, &table->sf_table);
+ kfree(table);
+}
+
+int mlx5_meddev_register(struct mlx5_eswitch *esw)
+{
+ if (!esw->mdev_table)
+ return 0;
+
+ rcu_assign_pointer(esw->mdev_table->dev, esw->dev);
+ return mdev_register_device(esw->dev->device, &mlx5_meddev_ops);
+}
+
+void mlx5_meddev_unregister(struct mlx5_eswitch *esw)
+{
+ if (!esw->mdev_table)
+ return;
+
+ rcu_assign_pointer(esw->mdev_table->dev, NULL);
+ synchronize_srcu(&esw->mdev_table->offloads_srcu);
+ /* At this point no new creation can begin, so it is safe to
+ * unergister with mdev.
+ */
+ mdev_unregister_device(esw->dev->device);
+}
+
+/* Check if meddev cleanup can be done or not.
+ * If possible to cleanup, mark that cleanup will be in progress
+ * so that no new creation can happen.
+ */
+bool mlx5_meddev_can_and_mark_cleanup(struct mlx5_eswitch *esw)
+{
+ struct mlx5_core_dev *dev = esw->dev;
+ struct mlx5_mdev_table *table;
+
+ if (!mlx5_core_is_sf_supported(dev) || !esw->mdev_table)
+ return true;
+
+ table = esw->mdev_table;
+
+ rcu_assign_pointer(esw->mdev_table->dev, NULL);
+ synchronize_srcu(&esw->mdev_table->offloads_srcu);
+
+ if (mlx5_get_free_sfs(esw->dev, &table->sf_table) !=
+ mlx5_core_max_sfs(esw->dev, &table->sf_table)) {
+ /* There are active SFs for the mdev, so
+ * revert back.
+ */
+ rcu_assign_pointer(esw->mdev_table->dev, dev);
+ return false;
+ }
+ return true;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
index fb4ba7be0051..99eb54d345a8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.c
@@ -182,3 +182,25 @@ void mlx5_sf_free(struct mlx5_core_dev *coredev, struct mlx5_sf_table *sf_table,
free_sf_id(sf_table, sf->idx);
kfree(sf);
}
+
+u16 mlx5_get_free_sfs(struct mlx5_core_dev *dev, struct mlx5_sf_table *sf_table)
+{
+ u16 free_sfs = 0;
+
+ if (!mlx5_core_is_sf_supported(dev))
+ return 0;
+
+ mutex_lock(&sf_table->lock);
+ if (sf_table->sf_id_bitmap)
+ free_sfs = sf_table->max_sfs -
+ bitmap_weight(sf_table->sf_id_bitmap,
+ sf_table->max_sfs);
+ mutex_unlock(&sf_table->lock);
+ return free_sfs;
+}
+
+u16 mlx5_core_max_sfs(const struct mlx5_core_dev *dev,
+ const struct mlx5_sf_table *sf_table)
+{
+ return mlx5_core_is_sf_supported(dev) ? sf_table->max_sfs : 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
index 1e1ba388504c..526a6795e984 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/meddev/sf.h
@@ -45,6 +45,24 @@ mlx5_sf_alloc(struct mlx5_core_dev *coredev, struct mlx5_sf_table *sf_table,
struct device *dev);
void mlx5_sf_free(struct mlx5_core_dev *coredev, struct mlx5_sf_table *sf_table,
struct mlx5_sf *sf);
+u16 mlx5_core_max_sfs(const struct mlx5_core_dev *dev,
+ const struct mlx5_sf_table *sf_table);
+u16 mlx5_get_free_sfs(struct mlx5_core_dev *dev,
+ struct mlx5_sf_table *sf_table);
+
+#else
+static inline u16 mlx5_core_max_sfs(const struct mlx5_core_dev *dev,
+ const struct mlx5_sf_table *sf_table)
+{
+ return 0;
+}
+
+static inline u16 mlx5_get_free_sfs(struct mlx5_core_dev *dev,
+ struct mlx5_sf_table *sf_table)
+{
+ return 0;
+}
+
#endif
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 4e6bdae3ebfa..12e8c2409ee4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -245,4 +245,36 @@ enum {
u8 mlx5_get_nic_state(struct mlx5_core_dev *dev);
void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state);
+
+#ifdef CONFIG_MLX5_MDEV
+void mlx5_meddev_init(struct mlx5_eswitch *esw);
+void mlx5_meddev_cleanup(struct mlx5_eswitch *esw);
+int mlx5_meddev_register(struct mlx5_eswitch *esw);
+void mlx5_meddev_unregister(struct mlx5_eswitch *esw);
+bool mlx5_meddev_can_and_mark_cleanup(struct mlx5_eswitch *esw);
+#else
+static inline void mlx5_meddev_init(struct mlx5_core_dev *dev)
+{
+}
+
+static inline void mlx5_meddev_cleanup(struct mlx5_core_dev *dev)
+{
+}
+
+static inline int mlx5_meddev_register(struct mlx5_eswitch *esw)
+{
+ return 0;
+}
+
+void mlx5_meddev_unregister(struct mlx5_eswitch *esw)
+{
+}
+
+static inline bool mlx5_meddev_can_and_mark_cleanup(struct mlx5_eswitch *esw)
+{
+ return true;
+}
+#endif
+
+struct mlx5_core_dev *mlx5_get_core_dev(const struct device *dev);
#endif /* __MLX5_CORE_H__ */
--
2.19.2
^ permalink raw reply related [flat|nested] 132+ messages in thread
* [PATCH net-next 07/19] vfio/mdev: Introduce sha1 based mdev alias
2019-11-07 16:08 ` [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port Parav Pandit
` (4 preceding siblings ...)
2019-11-07 16:08 ` [PATCH net-next 06/19] net/mlx5: Add support for mediated devices in switchdev mode Parav Pandit
@ 2019-11-07 16:08 ` Parav Pandit
2019-11-08 11:04 ` Jiri Pirko
2019-11-08 11:10 ` Cornelia Huck
2019-11-07 16:08 ` [PATCH net-next 08/19] vfio/mdev: Make mdev alias unique among all mdevs Parav Pandit
` (12 subsequent siblings)
18 siblings, 2 replies; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:08 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Parav Pandit
Some vendor drivers want an identifier for an mdev device that is
shorter than the UUID, due to length restrictions in the consumers of
that identifier.
Add a callback that allows a vendor driver to request an alias of a
specified length to be generated for an mdev device. If generated,
that alias is checked for collisions.
It is an optional attribute.
mdev alias is generated using sha1 from the mdev name.
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Parav Pandit <parav@mellanox.com>
---
drivers/vfio/mdev/mdev_core.c | 123 ++++++++++++++++++++++++++++++-
drivers/vfio/mdev/mdev_private.h | 5 +-
drivers/vfio/mdev/mdev_sysfs.c | 13 ++--
include/linux/mdev.h | 4 +
4 files changed, 135 insertions(+), 10 deletions(-)
diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
index b558d4cfd082..3bdff0469607 100644
--- a/drivers/vfio/mdev/mdev_core.c
+++ b/drivers/vfio/mdev/mdev_core.c
@@ -10,9 +10,11 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
+#include <linux/mm.h>
#include <linux/uuid.h>
#include <linux/sysfs.h>
#include <linux/mdev.h>
+#include <crypto/hash.h>
#include "mdev_private.h"
@@ -27,6 +29,8 @@ static struct class_compat *mdev_bus_compat_class;
static LIST_HEAD(mdev_list);
static DEFINE_MUTEX(mdev_list_lock);
+static struct crypto_shash *alias_hash;
+
struct device *mdev_parent_dev(struct mdev_device *mdev)
{
return mdev->parent->dev;
@@ -150,6 +154,16 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
return -EINVAL;
+ if (ops->get_alias_length) {
+ unsigned int digest_size;
+ unsigned int aligned_len;
+
+ aligned_len = roundup(ops->get_alias_length(), 2);
+ digest_size = crypto_shash_digestsize(alias_hash);
+ if (aligned_len / 2 > digest_size)
+ return -EINVAL;
+ }
+
dev = get_device(dev);
if (!dev)
return -EINVAL;
@@ -259,6 +273,7 @@ static void mdev_device_free(struct mdev_device *mdev)
mutex_unlock(&mdev_list_lock);
dev_dbg(&mdev->dev, "MDEV: destroying\n");
+ kfree(mdev->alias);
kfree(mdev);
}
@@ -269,18 +284,101 @@ static void mdev_device_release(struct device *dev)
mdev_device_free(mdev);
}
-int mdev_device_create(struct kobject *kobj,
- struct device *dev, const guid_t *uuid)
+static const char *
+generate_alias(const char *uuid, unsigned int max_alias_len)
+{
+ struct shash_desc *hash_desc;
+ unsigned int digest_size;
+ unsigned char *digest;
+ unsigned int alias_len;
+ char *alias;
+ int ret;
+
+ /*
+ * Align to multiple of 2 as bin2hex will generate
+ * even number of bytes.
+ */
+ alias_len = roundup(max_alias_len, 2);
+ alias = kzalloc(alias_len + 1, GFP_KERNEL);
+ if (!alias)
+ return ERR_PTR(-ENOMEM);
+
+ /* Allocate and init descriptor */
+ hash_desc = kvzalloc(sizeof(*hash_desc) +
+ crypto_shash_descsize(alias_hash),
+ GFP_KERNEL);
+ if (!hash_desc) {
+ ret = -ENOMEM;
+ goto desc_err;
+ }
+
+ hash_desc->tfm = alias_hash;
+
+ digest_size = crypto_shash_digestsize(alias_hash);
+
+ digest = kzalloc(digest_size, GFP_KERNEL);
+ if (!digest) {
+ ret = -ENOMEM;
+ goto digest_err;
+ }
+ ret = crypto_shash_init(hash_desc);
+ if (ret)
+ goto hash_err;
+
+ ret = crypto_shash_update(hash_desc, uuid, UUID_STRING_LEN);
+ if (ret)
+ goto hash_err;
+
+ ret = crypto_shash_final(hash_desc, digest);
+ if (ret)
+ goto hash_err;
+
+ bin2hex(alias, digest, min_t(unsigned int, digest_size, alias_len / 2));
+ /*
+ * When alias length is odd, zero out an additional last byte
+ * that bin2hex has copied.
+ */
+ if (max_alias_len % 2)
+ alias[max_alias_len] = 0;
+
+ kfree(digest);
+ kvfree(hash_desc);
+ return alias;
+
+hash_err:
+ kfree(digest);
+digest_err:
+ kvfree(hash_desc);
+desc_err:
+ kfree(alias);
+ return ERR_PTR(ret);
+}
+
+int mdev_device_create(struct kobject *kobj, struct device *dev,
+ const char *uuid_str, const guid_t *uuid)
{
int ret;
struct mdev_device *mdev, *tmp;
struct mdev_parent *parent;
struct mdev_type *type = to_mdev_type(kobj);
+ const char *alias = NULL;
parent = mdev_get_parent(type->parent);
if (!parent)
return -EINVAL;
+ if (parent->ops->get_alias_length) {
+ unsigned int alias_len;
+
+ alias_len = parent->ops->get_alias_length();
+ if (alias_len) {
+ alias = generate_alias(uuid_str, alias_len);
+ if (IS_ERR(alias)) {
+ ret = PTR_ERR(alias);
+ goto alias_fail;
+ }
+ }
+ }
mutex_lock(&mdev_list_lock);
/* Check for duplicate */
@@ -300,6 +398,12 @@ int mdev_device_create(struct kobject *kobj,
}
guid_copy(&mdev->uuid, uuid);
+ mdev->alias = alias;
+ /*
+ * At this point alias memory is owned by the mdev.
+ * Mark it NULL, so that only mdev can free it.
+ */
+ alias = NULL;
list_add(&mdev->next, &mdev_list);
mutex_unlock(&mdev_list_lock);
@@ -346,6 +450,8 @@ int mdev_device_create(struct kobject *kobj,
up_read(&parent->unreg_sem);
put_device(&mdev->dev);
mdev_fail:
+ kfree(alias);
+alias_fail:
mdev_put_parent(parent);
return ret;
}
@@ -406,7 +512,17 @@ EXPORT_SYMBOL(mdev_get_iommu_device);
static int __init mdev_init(void)
{
- return mdev_bus_register();
+ int ret;
+
+ alias_hash = crypto_alloc_shash("sha1", 0, 0);
+ if (!alias_hash)
+ return -ENOMEM;
+
+ ret = mdev_bus_register();
+ if (ret)
+ crypto_free_shash(alias_hash);
+
+ return ret;
}
static void __exit mdev_exit(void)
@@ -415,6 +531,7 @@ static void __exit mdev_exit(void)
class_compat_unregister(mdev_bus_compat_class);
mdev_bus_unregister();
+ crypto_free_shash(alias_hash);
}
module_init(mdev_init)
diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h
index 7d922950caaf..078fdaf7836e 100644
--- a/drivers/vfio/mdev/mdev_private.h
+++ b/drivers/vfio/mdev/mdev_private.h
@@ -32,6 +32,7 @@ struct mdev_device {
struct list_head next;
struct kobject *type_kobj;
struct device *iommu_device;
+ const char *alias;
bool active;
};
@@ -57,8 +58,8 @@ void parent_remove_sysfs_files(struct mdev_parent *parent);
int mdev_create_sysfs_files(struct device *dev, struct mdev_type *type);
void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type);
-int mdev_device_create(struct kobject *kobj,
- struct device *dev, const guid_t *uuid);
+int mdev_device_create(struct kobject *kobj, struct device *dev,
+ const char *uuid_str, const guid_t *uuid);
int mdev_device_remove(struct device *dev);
#endif /* MDEV_PRIVATE_H */
diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c
index 7570c7602ab4..43afe0e80b76 100644
--- a/drivers/vfio/mdev/mdev_sysfs.c
+++ b/drivers/vfio/mdev/mdev_sysfs.c
@@ -63,15 +63,18 @@ static ssize_t create_store(struct kobject *kobj, struct device *dev,
return -ENOMEM;
ret = guid_parse(str, &uuid);
- kfree(str);
if (ret)
- return ret;
+ goto err;
- ret = mdev_device_create(kobj, dev, &uuid);
+ ret = mdev_device_create(kobj, dev, str, &uuid);
if (ret)
- return ret;
+ goto err;
- return count;
+ ret = count;
+
+err:
+ kfree(str);
+ return ret;
}
MDEV_TYPE_ATTR_WO(create);
diff --git a/include/linux/mdev.h b/include/linux/mdev.h
index 0ce30ca78db0..06e162361df9 100644
--- a/include/linux/mdev.h
+++ b/include/linux/mdev.h
@@ -72,6 +72,9 @@ struct device *mdev_get_iommu_device(struct device *dev);
* @mmap: mmap callback
* @mdev: mediated device structure
* @vma: vma structure
+ * @get_alias_length: Optional: If a non-zero alias length is returned,
+ * generate an alias for this parent's mdevs based upon
+ * the mdev device name.
* Parent device that support mediated device should be registered with mdev
* module with mdev_parent_ops structure.
**/
@@ -92,6 +95,7 @@ struct mdev_parent_ops {
long (*ioctl)(struct mdev_device *mdev, unsigned int cmd,
unsigned long arg);
int (*mmap)(struct mdev_device *mdev, struct vm_area_struct *vma);
+ unsigned int (*get_alias_length)(void);
};
/* interface for exporting mdev supported type attributes */
--
2.19.2
^ permalink raw reply related [flat|nested] 132+ messages in thread
* [PATCH net-next 08/19] vfio/mdev: Make mdev alias unique among all mdevs
2019-11-07 16:08 ` [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port Parav Pandit
` (5 preceding siblings ...)
2019-11-07 16:08 ` [PATCH net-next 07/19] vfio/mdev: Introduce sha1 based mdev alias Parav Pandit
@ 2019-11-07 16:08 ` Parav Pandit
2019-11-08 10:49 ` Jiri Pirko
2019-11-07 16:08 ` [PATCH net-next 09/19] vfio/mdev: Expose mdev alias in sysfs tree Parav Pandit
` (11 subsequent siblings)
18 siblings, 1 reply; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:08 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Parav Pandit
Mdev alias should be unique among all the mdevs, so that when such alias
is used by the mdev users to derive other objects, there is no
collision in a given system.
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Parav Pandit <parav@mellanox.com>
---
drivers/vfio/mdev/mdev_core.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
index 3bdff0469607..c8cd40366783 100644
--- a/drivers/vfio/mdev/mdev_core.c
+++ b/drivers/vfio/mdev/mdev_core.c
@@ -388,6 +388,13 @@ int mdev_device_create(struct kobject *kobj, struct device *dev,
ret = -EEXIST;
goto mdev_fail;
}
+ if (alias && tmp->alias && !strcmp(alias, tmp->alias)) {
+ mutex_unlock(&mdev_list_lock);
+ ret = -EEXIST;
+ dev_dbg_ratelimited(dev, "Hash collision in alias creation for UUID %pUl\n",
+ uuid);
+ goto mdev_fail;
+ }
}
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
--
2.19.2
^ permalink raw reply related [flat|nested] 132+ messages in thread
* [PATCH net-next 09/19] vfio/mdev: Expose mdev alias in sysfs tree
2019-11-07 16:08 ` [PATCH net-next 01/19] net/mlx5: E-switch, Move devlink port close to eswitch port Parav Pandit
` (6 preceding siblings ...)
2019-11-07 16:08 ` [PATCH net-next 08/19] vfio/mdev: Make mdev alias unique among all mdevs Parav Pandit
@ 2019-11-07 16:08 ` Parav Pandit
2019-11-08 13:22 ` Jiri Pirko
2019-11-07 16:08 ` [PATCH net-next 10/19] vfio/mdev: Introduce an API mdev_alias Parav Pandit
` (10 subsequent siblings)
18 siblings, 1 reply; 132+ messages in thread
From: Parav Pandit @ 2019-11-07 16:08 UTC (permalink / raw)
To: alex.williamson, davem, kvm, netdev
Cc: saeedm, kwankhede, leon, cohuck, jiri, linux-rdma, Parav Pandit
Expose the optional alias for an mdev device as a sysfs attribute.
This way