diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2010-02-01 00:25:00 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-02 18:55:46 -0500 |
commit | cdaff1854f32ac9ddb4733530f617d32188665ed (patch) | |
tree | 5d1e7b5bcf656d0071840431f1f3cbc94b828e21 /drivers/net/qlcnic/qlcnic_init.c | |
parent | 7eb9855d68faabe0004ed18c2af1f0974d3c2c63 (diff) |
qlcnic: add loopback diagnostic test
Loopback test (offline) added in ethtool self test.
o Set device in loopback mode
o Send packets
o Process receive packets in qlcnic_process_rcv_ring_diag()
o Compare packets
o Reset device in normal mode.
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlcnic/qlcnic_init.c')
-rw-r--r-- | drivers/net/qlcnic/qlcnic_init.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 7ae8bcc1e439..ea00ab4d4feb 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c | |||
@@ -1464,3 +1464,78 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, | |||
1464 | spin_unlock(&rds_ring->lock); | 1464 | spin_unlock(&rds_ring->lock); |
1465 | } | 1465 | } |
1466 | 1466 | ||
1467 | static struct qlcnic_rx_buffer * | ||
1468 | qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, | ||
1469 | struct qlcnic_host_sds_ring *sds_ring, | ||
1470 | int ring, u64 sts_data0) | ||
1471 | { | ||
1472 | struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; | ||
1473 | struct qlcnic_rx_buffer *buffer; | ||
1474 | struct sk_buff *skb; | ||
1475 | struct qlcnic_host_rds_ring *rds_ring; | ||
1476 | int index, length, cksum, pkt_offset; | ||
1477 | |||
1478 | if (unlikely(ring >= adapter->max_rds_rings)) | ||
1479 | return NULL; | ||
1480 | |||
1481 | rds_ring = &recv_ctx->rds_rings[ring]; | ||
1482 | |||
1483 | index = qlcnic_get_sts_refhandle(sts_data0); | ||
1484 | if (unlikely(index >= rds_ring->num_desc)) | ||
1485 | return NULL; | ||
1486 | |||
1487 | buffer = &rds_ring->rx_buf_arr[index]; | ||
1488 | |||
1489 | length = qlcnic_get_sts_totallength(sts_data0); | ||
1490 | cksum = qlcnic_get_sts_status(sts_data0); | ||
1491 | pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0); | ||
1492 | |||
1493 | skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum); | ||
1494 | if (!skb) | ||
1495 | return buffer; | ||
1496 | |||
1497 | skb_put(skb, rds_ring->skb_size); | ||
1498 | |||
1499 | if (pkt_offset) | ||
1500 | skb_pull(skb, pkt_offset); | ||
1501 | |||
1502 | skb->truesize = skb->len + sizeof(struct sk_buff); | ||
1503 | |||
1504 | if (!qlcnic_check_loopback_buff(skb->data)) | ||
1505 | adapter->diag_cnt++; | ||
1506 | |||
1507 | dev_kfree_skb_any(skb); | ||
1508 | |||
1509 | return buffer; | ||
1510 | } | ||
1511 | |||
1512 | void | ||
1513 | qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring) | ||
1514 | { | ||
1515 | struct qlcnic_adapter *adapter = sds_ring->adapter; | ||
1516 | struct status_desc *desc; | ||
1517 | struct qlcnic_rx_buffer *rxbuf; | ||
1518 | u64 sts_data0; | ||
1519 | |||
1520 | int opcode, ring, desc_cnt; | ||
1521 | u32 consumer = sds_ring->consumer; | ||
1522 | |||
1523 | desc = &sds_ring->desc_head[consumer]; | ||
1524 | sts_data0 = le64_to_cpu(desc->status_desc_data[0]); | ||
1525 | |||
1526 | if (!(sts_data0 & STATUS_OWNER_HOST)) | ||
1527 | return; | ||
1528 | |||
1529 | desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0); | ||
1530 | opcode = qlcnic_get_sts_opcode(sts_data0); | ||
1531 | |||
1532 | ring = qlcnic_get_sts_type(sts_data0); | ||
1533 | rxbuf = qlcnic_process_rcv_diag(adapter, sds_ring, | ||
1534 | ring, sts_data0); | ||
1535 | |||
1536 | desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM); | ||
1537 | consumer = get_next_index(consumer, sds_ring->num_desc); | ||
1538 | |||
1539 | sds_ring->consumer = consumer; | ||
1540 | writel(consumer, sds_ring->crb_sts_consumer); | ||
1541 | } | ||