Skip to content

Commit

Permalink
mlx4_en: Added self diagnostics test implementation
Browse files Browse the repository at this point in the history
The selftest includes 5 features:
1. Interrupt test: Executing commands and receiving command completion
   on all our interrupt vectors.
2. Link test: Verifying we are connected to valid link partner.
3. Speed test: Check that we negotiated link speed correctly.
4. Registers test: Activate HW health check command.
5. Loopback test: Send a packet on loopback interface and catch it on RX side.

Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Yevgeny Petrilin authored and David S. Miller committed Aug 24, 2010
1 parent 3005ad4 commit e7c1c2c
Show file tree
Hide file tree
Showing 15 changed files with 388 additions and 27 deletions.
2 changes: 1 addition & 1 deletion drivers/net/mlx4/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
obj-$(CONFIG_MLX4_EN) += mlx4_en.o

mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \
en_resources.o en_netdev.o
en_resources.o en_netdev.o en_selftest.o
79 changes: 54 additions & 25 deletions drivers/net/mlx4/en_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,14 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
#define NUM_MAIN_STATS 21
#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS)

static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= {
"Interupt Test",
"Link Test",
"Speed Test",
"Register Test",
"Loopback Test",
};

static u32 mlx4_en_get_msglevel(struct net_device *dev)
{
return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable;
Expand All @@ -146,10 +154,15 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
{
struct mlx4_en_priv *priv = netdev_priv(dev);

if (sset != ETH_SS_STATS)
switch (sset) {
case ETH_SS_STATS:
return NUM_ALL_STATS +
(priv->tx_ring_num + priv->rx_ring_num) * 2;
case ETH_SS_TEST:
return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.loopback_support) * 2;
default:
return -EOPNOTSUPP;

return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2;
}
}

static void mlx4_en_get_ethtool_stats(struct net_device *dev,
Expand Down Expand Up @@ -181,37 +194,52 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,

}

static void mlx4_en_self_test(struct net_device *dev,
struct ethtool_test *etest, u64 *buf)
{
mlx4_en_ex_selftest(dev, &etest->flags, buf);
}

static void mlx4_en_get_strings(struct net_device *dev,
uint32_t stringset, uint8_t *data)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
int index = 0;
int i;

if (stringset != ETH_SS_STATS)
return;

/* Add main counters */
for (i = 0; i < NUM_MAIN_STATS; i++)
strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
for (i = 0; i < NUM_PORT_STATS; i++)
strcpy(data + (index++) * ETH_GSTRING_LEN,
switch (stringset) {
case ETH_SS_TEST:
for (i = 0; i < MLX4_EN_NUM_SELF_TEST - 2; i++)
strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
if (priv->mdev->dev->caps.loopback_support)
for (; i < MLX4_EN_NUM_SELF_TEST; i++)
strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
break;

case ETH_SS_STATS:
/* Add main counters */
for (i = 0; i < NUM_MAIN_STATS; i++)
strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
for (i = 0; i< NUM_PORT_STATS; i++)
strcpy(data + (index++) * ETH_GSTRING_LEN,
main_strings[i + NUM_MAIN_STATS]);
for (i = 0; i < priv->tx_ring_num; i++) {
sprintf(data + (index++) * ETH_GSTRING_LEN,
"tx%d_packets", i);
sprintf(data + (index++) * ETH_GSTRING_LEN,
"tx%d_bytes", i);
}
for (i = 0; i < priv->rx_ring_num; i++) {
sprintf(data + (index++) * ETH_GSTRING_LEN,
"rx%d_packets", i);
sprintf(data + (index++) * ETH_GSTRING_LEN,
"rx%d_bytes", i);
}
for (i = 0; i < NUM_PKT_STATS; i++)
strcpy(data + (index++) * ETH_GSTRING_LEN,
for (i = 0; i < priv->tx_ring_num; i++) {
sprintf(data + (index++) * ETH_GSTRING_LEN,
"tx%d_packets", i);
sprintf(data + (index++) * ETH_GSTRING_LEN,
"tx%d_bytes", i);
}
for (i = 0; i < priv->rx_ring_num; i++) {
sprintf(data + (index++) * ETH_GSTRING_LEN,
"rx%d_packets", i);
sprintf(data + (index++) * ETH_GSTRING_LEN,
"rx%d_bytes", i);
}
for (i = 0; i< NUM_PKT_STATS; i++)
strcpy(data + (index++) * ETH_GSTRING_LEN,
main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]);
break;
}
}

static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
Expand Down Expand Up @@ -439,6 +467,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_strings = mlx4_en_get_strings,
.get_sset_count = mlx4_en_get_sset_count,
.get_ethtool_stats = mlx4_en_get_ethtool_stats,
.self_test = mlx4_en_self_test,
.get_wol = mlx4_en_get_wol,
.get_msglevel = mlx4_en_get_msglevel,
.set_msglevel = mlx4_en_set_msglevel,
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/mlx4/en_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
mutex_unlock(&mdev->state_lock);
}

static u64 mlx4_en_mac_to_u64(u8 *addr)
u64 mlx4_en_mac_to_u64(u8 *addr)
{
u64 mac = 0;
int i;
Expand Down
32 changes: 32 additions & 0 deletions drivers/net/mlx4/en_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,38 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
return err;
}

int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port)
{
struct mlx4_en_query_port_context *qport_context;
struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]);
struct mlx4_en_port_state *state = &priv->port_state;
struct mlx4_cmd_mailbox *mailbox;
int err;

mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
if (IS_ERR(mailbox))
return PTR_ERR(mailbox);
memset(mailbox->buf, 0, sizeof(*qport_context));
err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0,
MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B);
if (err)
goto out;
qport_context = mailbox->buf;

/* This command is always accessed from Ethtool context
* already synchronized, no need in locking */
state->link_state = !!(qport_context->link_up & MLX4_EN_LINK_UP_MASK);
if ((qport_context->link_speed & MLX4_EN_SPEED_MASK) ==
MLX4_EN_1G_SPEED)
state->link_speed = 1000;
else
state->link_speed = 10000;
state->transciver = qport_context->transceiver;

out:
mlx4_free_cmd_mailbox(mdev->dev, mailbox);
return err;
}

int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
{
Expand Down
14 changes: 14 additions & 0 deletions drivers/net/mlx4/en_port.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ enum {
MLX4_MCAST_ENABLE = 2,
};

struct mlx4_en_query_port_context {
u8 link_up;
#define MLX4_EN_LINK_UP_MASK 0x80
u8 reserved;
__be16 mtu;
u8 reserved2;
u8 link_speed;
#define MLX4_EN_SPEED_MASK 0x3
#define MLX4_EN_1G_SPEED 0x2
u16 reserved3[5];
__be64 mac;
u8 transceiver;
};


struct mlx4_en_stat_out_mbox {
/* Received frames with a length of 64 octets */
Expand Down
20 changes: 20 additions & 0 deletions drivers/net/mlx4/en_rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,21 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
return skb;
}

static void validate_loopback(struct mlx4_en_priv *priv, struct sk_buff *skb)
{
int i;
int offset = ETH_HLEN;

for (i = 0; i < MLX4_LOOPBACK_TEST_PAYLOAD; i++, offset++) {
if (*(skb->data + offset) != (unsigned char) (i & 0xff))
goto out_loopback;
}
/* Loopback found */
priv->loopback_ok = 1;

out_loopback:
dev_kfree_skb_any(skb);
}

int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
{
Expand Down Expand Up @@ -655,6 +670,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
goto next;
}

if (unlikely(priv->validate_loopback)) {
validate_loopback(priv, skb);
goto next;
}

skb->ip_summed = ip_summed;
skb->protocol = eth_type_trans(skb, dev);
skb_record_rx_queue(skb, cq->ring);
Expand Down
Loading

0 comments on commit e7c1c2c

Please sign in to comment.