Commit 806a8df7 authored by Dragos Tatulea's avatar Dragos Tatulea Committed by Saeed Mahameed

net/mlx5e: IPoIB, Block queue count configuration when sub interfaces are present

PKEY sub interfaces share the receive queues with the parent interface.
While setting the sub interface queue count is not supported, it is
currently possible to change the number of queues of the parent interface.
Thus we can end up with inconsistent queue sizes between the parent and its
sub interfaces.

This change disallows setting the queue count on the parent interface when
sub interfaces are present.

This is achieved by introducing an explicit reference to the parent netdev
in the mlx5i_priv of the child interface. An additional counter is also
required on the parent side to detect when sub interfaces are attached and
for proper cleanup.

The rtnl lock is taken during the ethtool op and the sub interface
ndo_init/uninit ops. There is no race here around counting the sub
interfaces, reading the sub interfaces and setting the number of
channels. The ASSERT_RTNL was added to document that.

Fixes: be98737a ("net/mlx5e: Use dynamic per-channel allocations in stats")
Signed-off-by: default avatarDragos Tatulea <dtatulea@nvidia.com>
Reviewed-by: default avatarTariq Toukan <tariqt@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent ab4b01bf
......@@ -90,9 +90,21 @@ static void mlx5i_get_ringparam(struct net_device *dev,
static int mlx5i_set_channels(struct net_device *dev,
struct ethtool_channels *ch)
{
struct mlx5e_priv *priv = mlx5i_epriv(dev);
struct mlx5i_priv *ipriv = netdev_priv(dev);
struct mlx5e_priv *epriv = mlx5i_epriv(dev);
/* rtnl lock protects from race between this ethtool op and sub
* interface ndo_init/uninit.
*/
ASSERT_RTNL();
if (ipriv->num_sub_interfaces > 0) {
mlx5_core_warn(epriv->mdev,
"can't change number of channels for interfaces with sub interfaces (%u)\n",
ipriv->num_sub_interfaces);
return -EINVAL;
}
return mlx5e_ethtool_set_channels(priv, ch);
return mlx5e_ethtool_set_channels(epriv, ch);
}
static void mlx5i_get_channels(struct net_device *dev,
......
......@@ -160,6 +160,44 @@ void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
stats->tx_dropped = sstats->tx_queue_dropped;
}
struct net_device *mlx5i_parent_get(struct net_device *netdev)
{
struct mlx5e_priv *priv = mlx5i_epriv(netdev);
struct mlx5i_priv *ipriv, *parent_ipriv;
struct net_device *parent_dev;
int parent_ifindex;
ipriv = priv->ppriv;
parent_ifindex = netdev->netdev_ops->ndo_get_iflink(netdev);
parent_dev = dev_get_by_index(dev_net(netdev), parent_ifindex);
if (!parent_dev)
return NULL;
parent_ipriv = netdev_priv(parent_dev);
ASSERT_RTNL();
parent_ipriv->num_sub_interfaces++;
ipriv->parent_dev = parent_dev;
return parent_dev;
}
void mlx5i_parent_put(struct net_device *netdev)
{
struct mlx5e_priv *priv = mlx5i_epriv(netdev);
struct mlx5i_priv *ipriv, *parent_ipriv;
ipriv = priv->ppriv;
parent_ipriv = netdev_priv(ipriv->parent_dev);
ASSERT_RTNL();
parent_ipriv->num_sub_interfaces--;
dev_put(ipriv->parent_dev);
}
int mlx5i_init_underlay_qp(struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
......
......@@ -54,9 +54,11 @@ struct mlx5i_priv {
struct rdma_netdev rn; /* keep this first */
u32 qpn;
bool sub_interface;
u32 num_sub_interfaces;
u32 qkey;
u16 pkey_index;
struct mlx5i_pkey_qpn_ht *qpn_htbl;
struct net_device *parent_dev;
char *mlx5e_priv[];
};
......@@ -117,5 +119,9 @@ void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5_av *av, u32 dqpn, u32 dqkey, bool xmit_more);
void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats);
/* Reference management for child to parent interfaces. */
struct net_device *mlx5i_parent_get(struct net_device *netdev);
void mlx5i_parent_put(struct net_device *netdev);
#endif /* CONFIG_MLX5_CORE_IPOIB */
#endif /* __MLX5E_IPOB_H__ */
......@@ -158,21 +158,19 @@ static int mlx5i_pkey_dev_init(struct net_device *dev)
struct mlx5e_priv *priv = mlx5i_epriv(dev);
struct mlx5i_priv *ipriv, *parent_ipriv;
struct net_device *parent_dev;
int parent_ifindex;
ipriv = priv->ppriv;
/* Get QPN to netdevice hash table from parent */
parent_ifindex = dev->netdev_ops->ndo_get_iflink(dev);
parent_dev = dev_get_by_index(dev_net(dev), parent_ifindex);
/* Link to parent */
parent_dev = mlx5i_parent_get(dev);
if (!parent_dev) {
mlx5_core_warn(priv->mdev, "failed to get parent device\n");
return -EINVAL;
}
/* Get QPN to netdevice hash table from parent */
parent_ipriv = netdev_priv(parent_dev);
ipriv->qpn_htbl = parent_ipriv->qpn_htbl;
dev_put(parent_dev);
return mlx5i_dev_init(dev);
}
......@@ -184,6 +182,7 @@ static int mlx5i_pkey_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static void mlx5i_pkey_dev_cleanup(struct net_device *netdev)
{
mlx5i_parent_put(netdev);
return mlx5i_dev_cleanup(netdev);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment