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

Commit 6f2e0d2c authored by Eugenia Emantayev's avatar Eugenia Emantayev Committed by David S. Miller
Browse files

net/mlx4: Fix firmware command timeout during interrupt test



Currently interrupt test that is part of ethtool selftest runs the
check over all interrupt vectors of the device.
In mlx4_en package part of interrupt vectors are uninitialized since
mlx4_ib doesn't exist. This causes NOP FW command to time out.
Change logic to test current port interrupt vectors only.

Signed-off-by: default avatarEugenia Emantayev <eugenia@mellanox.com>
Signed-off-by: default avatarTariq Toukan <tariqt@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 81d18419
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -118,6 +118,29 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
	return !loopback_ok;
}

static int mlx4_en_test_interrupts(struct mlx4_en_priv *priv)
{
	struct mlx4_en_dev *mdev = priv->mdev;
	int err = 0;
	int i = 0;

	err = mlx4_test_async(mdev->dev);
	/* When not in MSI_X or slave, test only async */
	if (!(mdev->dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(mdev->dev))
		return err;

	/* A loop over all completion vectors of current port,
	 * for each vector check whether it works by mapping command
	 * completions to that vector and performing a NOP command
	 */
	for (i = 0; i < priv->rx_ring_num; i++) {
		err = mlx4_test_interrupt(mdev->dev, priv->rx_cq[i]->vector);
		if (err)
			break;
	}

	return err;
}

static int mlx4_en_test_link(struct mlx4_en_priv *priv)
{
@@ -151,7 +174,6 @@ static int mlx4_en_test_speed(struct mlx4_en_priv *priv)
void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf)
{
	struct mlx4_en_priv *priv = netdev_priv(dev);
	struct mlx4_en_dev *mdev = priv->mdev;
	int i, carrier_ok;

	memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST);
@@ -177,7 +199,7 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf)
			netif_carrier_on(dev);

	}
	buf[0] = mlx4_test_interrupts(mdev->dev);
	buf[0] = mlx4_en_test_interrupts(priv);
	buf[1] = mlx4_en_test_link(priv);
	buf[2] = mlx4_en_test_speed(priv);

+29 −33
Original line number Diff line number Diff line
@@ -1361,53 +1361,49 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
	kfree(priv->eq_table.uar_map);
}

/* A test that verifies that we can accept interrupts on all
 * the irq vectors of the device.
/* A test that verifies that we can accept interrupts
 * on the vector allocated for asynchronous events
 */
int mlx4_test_async(struct mlx4_dev *dev)
{
	return mlx4_NOP(dev);
}
EXPORT_SYMBOL(mlx4_test_async);

/* A test that verifies that we can accept interrupts
 * on the given irq vector of the tested port.
 * Interrupts are checked using the NOP command.
 */
int mlx4_test_interrupts(struct mlx4_dev *dev)
int mlx4_test_interrupt(struct mlx4_dev *dev, int vector)
{
	struct mlx4_priv *priv = mlx4_priv(dev);
	int i;
	int err;

	err = mlx4_NOP(dev);
	/* When not in MSI_X, there is only one irq to check */
	if (!(dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(dev))
		return err;

	/* A loop over all completion vectors, for each vector we will check
	 * whether it works by mapping command completions to that vector
	 * and performing a NOP command
	 */
	for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) {
		/* Make sure request_irq was called */
		if (!priv->eq_table.eq[i].have_irq)
			continue;

	/* Temporary use polling for command completions */
	mlx4_cmd_use_polling(dev);

	/* Map the new eq to handle all asynchronous events */
	err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0,
				  priv->eq_table.eq[i].eqn);
			  priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn);
	if (err) {
		mlx4_warn(dev, "Failed mapping eq for interrupt test\n");
			mlx4_cmd_use_events(dev);
			break;
		goto out;
	}

	/* Go back to using events */
	mlx4_cmd_use_events(dev);
	err = mlx4_NOP(dev);
	}

	/* Return to default */
	mlx4_cmd_use_polling(dev);
out:
	mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0,
		    priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
	mlx4_cmd_use_events(dev);

	return err;
}
EXPORT_SYMBOL(mlx4_test_interrupts);
EXPORT_SYMBOL(mlx4_test_interrupt);

bool mlx4_is_eq_vector_valid(struct mlx4_dev *dev, u8 port, int vector)
{
+2 −1
Original line number Diff line number Diff line
@@ -1399,7 +1399,8 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
		    u32 *lkey, u32 *rkey);
int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr);
int mlx4_SYNC_TPT(struct mlx4_dev *dev);
int mlx4_test_interrupts(struct mlx4_dev *dev);
int mlx4_test_interrupt(struct mlx4_dev *dev, int vector);
int mlx4_test_async(struct mlx4_dev *dev);
int mlx4_query_diag_counters(struct mlx4_dev *dev, u8 op_modifier,
			     const u32 offset[], u32 value[],
			     size_t array_len, u8 port);