Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f108c887 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'devlink-Introduce-PCI-PF-VF-ports-and-attributes'

Parav Pandit says:

====================
devlink: Introduce PCI PF, VF ports and attributes

This patchset carry forwards the work initiated in [1] and discussion
futher concluded at [2].

To improve visibility of representor netdevice, its association with
PF or VF, physical port, two new devlink port flavours are added as
PCI PF and PCI VF ports.

A sample eswitch view can be seen below, which will be futher extended to
mdev subdevices of a PCI function in future.

Patch-1 moves physical port's attribute to new structure
Patch-2 enhances netlink response to consider port flavour
Patch-3,4 extends devlink port attributes and port flavour
Patch-5 extends mlx5 driver to register devlink ports for PF, VF and
physical link.

                                +---+      +---+
                              vf|   |      |   | pf
                                +-+-+      +-+-+
physical link <---------+         |          |
                        |         |          |
                        |         |          |
                      +-+-+     +-+-+      +-+-+
                      | 1 |     | 2 |      | 3 |
                   +--+---+-----+---+------+---+--+
                   |  physical   vf         pf    |
                   |  port       port       port  |
                   |                              |
                   |             eswitch          |
                   |                              |
                   +------------------------------+

[1] https://www.spinics.net/lists/netdev/msg555797.html
[2] https://marc.info/?l=linux-netdev&m=155354609408485&w=2



Changelog:
v5->v6:
 - Fixed port flavour check order for PCI PF vs other flavours in
   netlink response.
 - Changed 'physical' to 'phys'.
v4->v5:
 - Split first patch to two patches to handle netlink response in
   separate patch.
 - Corrected typo 'otwerwise' to 'otherwise' in patches 3 and 4.
v3->v4:
 - Addressed comments from Jiri.
 - Split first patch to two patches.
 - Renamed phys_port to physical to be consistent with pci_pf.
 - Removed port_number from __devlink_port_attrs_set and moved
   assignment to caller function.
 - Used capital letter while moving old comment to new structure.
 - Removed helper function is_devlink_phy_port_num_supported().
v2->v3:
 - Made port_number and split_port_number applicable only to
   physical port flavours.
v1->v2:
 - Updated new APIs and mlx5 driver to drop port_number for PF, VF
   attributes
 - Updated port_number comment for its usage
 - Limited putting port_number to physical ports
====================

Reviewed-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b14a260e f60f315d
Loading
Loading
Loading
Loading
+77 −31
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <net/act_api.h>
#include <net/netevent.h>
#include <net/arp.h>
#include <net/devlink.h>

#include "eswitch.h"
#include "en.h"
@@ -1119,32 +1120,6 @@ static int mlx5e_rep_close(struct net_device *dev)
	return ret;
}

static int mlx5e_rep_get_phys_port_name(struct net_device *dev,
					char *buf, size_t len)
{
	struct mlx5e_priv *priv = netdev_priv(dev);
	struct mlx5e_rep_priv *rpriv = priv->ppriv;
	struct mlx5_eswitch_rep *rep = rpriv->rep;
	unsigned int fn;
	int ret;

	fn = PCI_FUNC(priv->mdev->pdev->devfn);
	if (fn >= MLX5_MAX_PORTS)
		return -EOPNOTSUPP;

	if (rep->vport == MLX5_VPORT_UPLINK)
		ret = snprintf(buf, len, "p%d", fn);
	else if (rep->vport == MLX5_VPORT_PF)
		ret = snprintf(buf, len, "pf%d", fn);
	else
		ret = snprintf(buf, len, "pf%dvf%d", fn, rep->vport - 1);

	if (ret >= len)
		return -EOPNOTSUPP;

	return 0;
}

static int
mlx5e_rep_setup_tc_cls_flower(struct mlx5e_priv *priv,
			      struct tc_cls_flower_offload *cls_flower, int flags)
@@ -1298,17 +1273,24 @@ static int mlx5e_uplink_rep_set_vf_vlan(struct net_device *dev, int vf, u16 vlan
	return 0;
}

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;

	return &rpriv->dl_port;
}

static const struct net_device_ops mlx5e_netdev_ops_rep = {
	.ndo_open                = mlx5e_rep_open,
	.ndo_stop                = mlx5e_rep_close,
	.ndo_start_xmit          = mlx5e_xmit,
	.ndo_get_phys_port_name  = mlx5e_rep_get_phys_port_name,
	.ndo_setup_tc            = mlx5e_rep_setup_tc,
	.ndo_get_devlink_port = mlx5e_get_devlink_port,
	.ndo_get_stats64         = mlx5e_rep_get_stats,
	.ndo_has_offload_stats	 = mlx5e_rep_has_offload_stats,
	.ndo_get_offload_stats	 = mlx5e_rep_get_offload_stats,
	.ndo_change_mtu          = mlx5e_rep_change_mtu,
	.ndo_get_port_parent_id	 = mlx5e_rep_get_port_parent_id,
};

static const struct net_device_ops mlx5e_netdev_ops_uplink_rep = {
@@ -1316,8 +1298,8 @@ static const struct net_device_ops mlx5e_netdev_ops_uplink_rep = {
	.ndo_stop                = mlx5e_close,
	.ndo_start_xmit          = mlx5e_xmit,
	.ndo_set_mac_address     = mlx5e_uplink_rep_set_mac,
	.ndo_get_phys_port_name  = mlx5e_rep_get_phys_port_name,
	.ndo_setup_tc            = mlx5e_rep_setup_tc,
	.ndo_get_devlink_port = mlx5e_get_devlink_port,
	.ndo_get_stats64         = mlx5e_get_stats,
	.ndo_has_offload_stats	 = mlx5e_rep_has_offload_stats,
	.ndo_get_offload_stats	 = mlx5e_rep_get_offload_stats,
@@ -1330,7 +1312,6 @@ static const struct net_device_ops mlx5e_netdev_ops_uplink_rep = {
	.ndo_get_vf_config       = mlx5e_get_vf_config,
	.ndo_get_vf_stats        = mlx5e_get_vf_stats,
	.ndo_set_vf_vlan         = mlx5e_uplink_rep_set_vf_vlan,
	.ndo_get_port_parent_id	 = mlx5e_rep_get_port_parent_id,
	.ndo_set_features        = mlx5e_set_features,
};

@@ -1731,6 +1712,55 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
	.max_tc			= MLX5E_MAX_NUM_TC,
};

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 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 = {};
	int ret;

	if (!is_devlink_port_supported(dev, rpriv))
		return 0;

	ret = mlx5e_rep_get_port_parent_id(rpriv->netdev, &ppid);
	if (ret)
		return ret;

	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);
	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);
	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);

	return devlink_port_register(devlink, &rpriv->dl_port, rep->vport);
}

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)
@@ -1782,15 +1812,27 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
		goto err_detach_netdev;
	}

	err = register_devlink_port(dev, rpriv);
	if (err) {
		esw_warn(dev, "Failed to register devlink port %d\n",
			 rep->vport);
		goto err_neigh_cleanup;
	}

	err = register_netdev(netdev);
	if (err) {
		pr_warn("Failed to register representor netdev for vport %d\n",
			rep->vport);
		goto err_neigh_cleanup;
		goto err_devlink_cleanup;
	}

	if (is_devlink_port_supported(dev, rpriv))
		devlink_port_type_eth_set(&rpriv->dl_port, netdev);
	return 0;

err_devlink_cleanup:
	unregister_devlink_port(dev, rpriv);

err_neigh_cleanup:
	mlx5e_rep_neigh_cleanup(rpriv);

@@ -1813,9 +1855,13 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
	struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
	struct net_device *netdev = rpriv->netdev;
	struct mlx5e_priv *priv = netdev_priv(netdev);
	struct mlx5_core_dev *dev = priv->mdev;
	void *ppriv = priv->ppriv;

	if (is_devlink_port_supported(dev, rpriv))
		devlink_port_type_clear(&rpriv->dl_port);
	unregister_netdev(netdev);
	unregister_devlink_port(dev, rpriv);
	mlx5e_rep_neigh_cleanup(rpriv);
	mlx5e_detach_netdev(priv);
	if (rep->vport == MLX5_VPORT_UPLINK)
+1 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ struct mlx5e_rep_priv {
	struct mlx5_flow_handle *vport_rx_rule;
	struct list_head       vport_sqs_list;
	struct mlx5_rep_uplink_priv uplink_priv; /* valid for uplink rep */
	struct devlink_port dl_port;
};

static inline
+29 −2
Original line number Diff line number Diff line
@@ -38,14 +38,34 @@ struct devlink {
	char priv[0] __aligned(NETDEV_ALIGN);
};

struct devlink_port_phys_attrs {
	u32 port_number; /* Same value as "split group".
			  * A physical port which is visible to the user
			  * for a given port flavour.
			  */
	u32 split_subport_number;
};

struct devlink_port_pci_pf_attrs {
	u16 pf;	/* Associated PCI PF for this port. */
};

struct devlink_port_pci_vf_attrs {
	u16 pf;	/* Associated PCI PF for this port. */
	u16 vf;	/* Associated PCI VF for of the PCI PF for this port. */
};

struct devlink_port_attrs {
	u8 set:1,
	   split:1,
	   switch_port:1;
	enum devlink_port_flavour flavour;
	u32 port_number; /* same value as "split group" */
	u32 split_subport_number;
	struct netdev_phys_item_id switch_id;
	union {
		struct devlink_port_phys_attrs phys;
		struct devlink_port_pci_pf_attrs pci_pf;
		struct devlink_port_pci_vf_attrs pci_vf;
	};
};

struct devlink_port {
@@ -590,6 +610,13 @@ void devlink_port_attrs_set(struct devlink_port *devlink_port,
			    u32 split_subport_number,
			    const unsigned char *switch_id,
			    unsigned char switch_id_len);
void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port,
				   const unsigned char *switch_id,
				   unsigned char switch_id_len, u16 pf);
void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
				   const unsigned char *switch_id,
				   unsigned char switch_id_len,
				   u16 pf, u16 vf);
int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
			u32 size, u16 ingress_pools_count,
			u16 egress_pools_count, u16 ingress_tc_count,
+11 −0
Original line number Diff line number Diff line
@@ -169,6 +169,14 @@ enum devlink_port_flavour {
	DEVLINK_PORT_FLAVOUR_DSA, /* Distributed switch architecture
				   * interconnect port.
				   */
	DEVLINK_PORT_FLAVOUR_PCI_PF, /* Represents eswitch port for
				      * the PCI PF. It is an internal
				      * port that faces the PCI PF.
				      */
	DEVLINK_PORT_FLAVOUR_PCI_VF, /* Represents eswitch port
				      * for the PCI VF. It is an internal
				      * port that faces the PCI VF.
				      */
};

enum devlink_param_cmode {
@@ -337,6 +345,9 @@ enum devlink_attr {
	DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,	/* u64 */
	DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,	/* u64 */

	DEVLINK_ATTR_PORT_PCI_PF_NUMBER,	/* u16 */
	DEVLINK_ATTR_PORT_PCI_VF_NUMBER,	/* u16 */

	/* add new attributes above here, update the policy in devlink.c */

	__DEVLINK_ATTR_MAX,
+114 −20
Original line number Diff line number Diff line
@@ -515,14 +515,31 @@ static int devlink_nl_port_attrs_put(struct sk_buff *msg,
		return 0;
	if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
		return -EMSGSIZE;
	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER, attrs->port_number))
	if (devlink_port->attrs.flavour == DEVLINK_PORT_FLAVOUR_PCI_PF) {
		if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
				attrs->pci_pf.pf))
			return -EMSGSIZE;
	} else if (devlink_port->attrs.flavour == DEVLINK_PORT_FLAVOUR_PCI_VF) {
		if (nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
				attrs->pci_vf.pf) ||
		    nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER,
				attrs->pci_vf.vf))
			return -EMSGSIZE;
	}
	if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PHYSICAL &&
	    devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
	    devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA)
		return 0;
	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
			attrs->phys.port_number))
		return -EMSGSIZE;
	if (!attrs->split)
		return 0;
	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP, attrs->port_number))
	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
			attrs->phys.port_number))
		return -EMSGSIZE;
	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
			attrs->split_subport_number))
			attrs->phys.split_subport_number))
		return -EMSGSIZE;
	return 0;
}
@@ -5738,6 +5755,29 @@ void devlink_port_type_clear(struct devlink_port *devlink_port)
}
EXPORT_SYMBOL_GPL(devlink_port_type_clear);

static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
				    enum devlink_port_flavour flavour,
				    const unsigned char *switch_id,
				    unsigned char switch_id_len)
{
	struct devlink_port_attrs *attrs = &devlink_port->attrs;

	if (WARN_ON(devlink_port->registered))
		return -EEXIST;
	attrs->set = true;
	attrs->flavour = flavour;
	if (switch_id) {
		attrs->switch_port = true;
		if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
			switch_id_len = MAX_PHYS_ITEM_ID_LEN;
		memcpy(attrs->switch_id.id, switch_id, switch_id_len);
		attrs->switch_id.id_len = switch_id_len;
	} else {
		attrs->switch_port = false;
	}
	return 0;
}

/**
 *	devlink_port_attrs_set - Set port attributes
 *
@@ -5760,26 +5800,72 @@ void devlink_port_attrs_set(struct devlink_port *devlink_port,
			    unsigned char switch_id_len)
{
	struct devlink_port_attrs *attrs = &devlink_port->attrs;
	int ret;

	if (WARN_ON(devlink_port->registered))
	ret = __devlink_port_attrs_set(devlink_port, flavour,
				       switch_id, switch_id_len);
	if (ret)
		return;
	attrs->set = true;
	attrs->flavour = flavour;
	attrs->port_number = port_number;
	attrs->split = split;
	attrs->split_subport_number = split_subport_number;
	if (switch_id) {
		attrs->switch_port = true;
		if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
			switch_id_len = MAX_PHYS_ITEM_ID_LEN;
		memcpy(attrs->switch_id.id, switch_id, switch_id_len);
		attrs->switch_id.id_len = switch_id_len;
	} else {
		attrs->switch_port = false;
	}
	attrs->phys.port_number = port_number;
	attrs->phys.split_subport_number = split_subport_number;
}
EXPORT_SYMBOL_GPL(devlink_port_attrs_set);

/**
 *	devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
 *
 *	@devlink_port: devlink port
 *	@pf: associated PF for the devlink port instance
 *	@switch_id: if the port is part of switch, this is buffer with ID,
 *	            otherwise this is NULL
 *	@switch_id_len: length of the switch_id buffer
 */
void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port,
				   const unsigned char *switch_id,
				   unsigned char switch_id_len, u16 pf)
{
	struct devlink_port_attrs *attrs = &devlink_port->attrs;
	int ret;

	ret = __devlink_port_attrs_set(devlink_port,
				       DEVLINK_PORT_FLAVOUR_PCI_PF,
				       switch_id, switch_id_len);
	if (ret)
		return;

	attrs->pci_pf.pf = pf;
}
EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);

/**
 *	devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
 *
 *	@devlink_port: devlink port
 *	@pf: associated PF for the devlink port instance
 *	@vf: associated VF of a PF for the devlink port instance
 *	@switch_id: if the port is part of switch, this is buffer with ID,
 *	            otherwise this is NULL
 *	@switch_id_len: length of the switch_id buffer
 */
void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
				   const unsigned char *switch_id,
				   unsigned char switch_id_len,
				   u16 pf, u16 vf)
{
	struct devlink_port_attrs *attrs = &devlink_port->attrs;
	int ret;

	ret = __devlink_port_attrs_set(devlink_port,
				       DEVLINK_PORT_FLAVOUR_PCI_VF,
				       switch_id, switch_id_len);
	if (ret)
		return;
	attrs->pci_vf.pf = pf;
	attrs->pci_vf.vf = vf;
}
EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);

static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
					     char *name, size_t len)
{
@@ -5792,10 +5878,11 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
	switch (attrs->flavour) {
	case DEVLINK_PORT_FLAVOUR_PHYSICAL:
		if (!attrs->split)
			n = snprintf(name, len, "p%u", attrs->port_number);
			n = snprintf(name, len, "p%u", attrs->phys.port_number);
		else
			n = snprintf(name, len, "p%us%u", attrs->port_number,
				     attrs->split_subport_number);
			n = snprintf(name, len, "p%us%u",
				     attrs->phys.port_number,
				     attrs->phys.split_subport_number);
		break;
	case DEVLINK_PORT_FLAVOUR_CPU:
	case DEVLINK_PORT_FLAVOUR_DSA:
@@ -5804,6 +5891,13 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
		 */
		WARN_ON(1);
		return -EINVAL;
	case DEVLINK_PORT_FLAVOUR_PCI_PF:
		n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
		break;
	case DEVLINK_PORT_FLAVOUR_PCI_VF:
		n = snprintf(name, len, "pf%uvf%u",
			     attrs->pci_vf.pf, attrs->pci_vf.vf);
		break;
	}

	if (n >= len)