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: Eugenia Emantayev <eugenia@mellanox.com> Signed-off-by: Tariq Toukan <tariqt@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
81d184199e
commit
6f2e0d2c3b
@ -118,6 +118,29 @@ mlx4_en_test_loopback_exit:
|
||||
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);
|
||||
|
||||
|
@ -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;
|
||||
/* Temporary use polling for command completions */
|
||||
mlx4_cmd_use_polling(dev);
|
||||
|
||||
/* 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);
|
||||
if (err) {
|
||||
mlx4_warn(dev, "Failed mapping eq for interrupt test\n");
|
||||
mlx4_cmd_use_events(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Go back to using events */
|
||||
mlx4_cmd_use_events(dev);
|
||||
err = mlx4_NOP(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[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn);
|
||||
if (err) {
|
||||
mlx4_warn(dev, "Failed mapping eq for interrupt test\n");
|
||||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user