diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/tg3.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 49cb7b3e2835..2a771fd4c7cd 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -7576,6 +7576,117 @@ static int tg3_test_memory(struct tg3 *tp) | |||
7576 | return err; | 7576 | return err; |
7577 | } | 7577 | } |
7578 | 7578 | ||
7579 | static int tg3_test_loopback(struct tg3 *tp) | ||
7580 | { | ||
7581 | u32 mac_mode, send_idx, rx_start_idx, rx_idx, tx_idx, opaque_key; | ||
7582 | u32 desc_idx; | ||
7583 | struct sk_buff *skb, *rx_skb; | ||
7584 | u8 *tx_data; | ||
7585 | dma_addr_t map; | ||
7586 | int num_pkts, tx_len, rx_len, i, err; | ||
7587 | struct tg3_rx_buffer_desc *desc; | ||
7588 | |||
7589 | if (!netif_running(tp->dev)) | ||
7590 | return -ENODEV; | ||
7591 | |||
7592 | err = -EIO; | ||
7593 | |||
7594 | tg3_abort_hw(tp, 1); | ||
7595 | |||
7596 | /* Clearing this flag to keep interrupts disabled */ | ||
7597 | tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; | ||
7598 | tg3_reset_hw(tp); | ||
7599 | |||
7600 | mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | | ||
7601 | MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY | | ||
7602 | MAC_MODE_PORT_MODE_GMII; | ||
7603 | tw32(MAC_MODE, mac_mode); | ||
7604 | |||
7605 | tx_len = 1514; | ||
7606 | skb = dev_alloc_skb(tx_len); | ||
7607 | tx_data = skb_put(skb, tx_len); | ||
7608 | memcpy(tx_data, tp->dev->dev_addr, 6); | ||
7609 | memset(tx_data + 6, 0x0, 8); | ||
7610 | |||
7611 | tw32(MAC_RX_MTU_SIZE, tx_len + 4); | ||
7612 | |||
7613 | for (i = 14; i < tx_len; i++) | ||
7614 | tx_data[i] = (u8) (i & 0xff); | ||
7615 | |||
7616 | map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); | ||
7617 | |||
7618 | tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | | ||
7619 | HOSTCC_MODE_NOW); | ||
7620 | |||
7621 | udelay(10); | ||
7622 | |||
7623 | rx_start_idx = tp->hw_status->idx[0].rx_producer; | ||
7624 | |||
7625 | send_idx = 0; | ||
7626 | num_pkts = 0; | ||
7627 | |||
7628 | tg3_set_txd(tp, send_idx, map, tx_len, 0, 1); | ||
7629 | |||
7630 | send_idx++; | ||
7631 | num_pkts++; | ||
7632 | |||
7633 | tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, send_idx); | ||
7634 | tr32(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW); | ||
7635 | |||
7636 | udelay(10); | ||
7637 | |||
7638 | for (i = 0; i < 10; i++) { | ||
7639 | tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | | ||
7640 | HOSTCC_MODE_NOW); | ||
7641 | |||
7642 | udelay(10); | ||
7643 | |||
7644 | tx_idx = tp->hw_status->idx[0].tx_consumer; | ||
7645 | rx_idx = tp->hw_status->idx[0].rx_producer; | ||
7646 | if ((tx_idx == send_idx) && | ||
7647 | (rx_idx == (rx_start_idx + num_pkts))) | ||
7648 | break; | ||
7649 | } | ||
7650 | |||
7651 | pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE); | ||
7652 | dev_kfree_skb(skb); | ||
7653 | |||
7654 | if (tx_idx != send_idx) | ||
7655 | goto out; | ||
7656 | |||
7657 | if (rx_idx != rx_start_idx + num_pkts) | ||
7658 | goto out; | ||
7659 | |||
7660 | desc = &tp->rx_rcb[rx_start_idx]; | ||
7661 | desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; | ||
7662 | opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; | ||
7663 | if (opaque_key != RXD_OPAQUE_RING_STD) | ||
7664 | goto out; | ||
7665 | |||
7666 | if ((desc->err_vlan & RXD_ERR_MASK) != 0 && | ||
7667 | (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) | ||
7668 | goto out; | ||
7669 | |||
7670 | rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; | ||
7671 | if (rx_len != tx_len) | ||
7672 | goto out; | ||
7673 | |||
7674 | rx_skb = tp->rx_std_buffers[desc_idx].skb; | ||
7675 | |||
7676 | map = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], mapping); | ||
7677 | pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); | ||
7678 | |||
7679 | for (i = 14; i < tx_len; i++) { | ||
7680 | if (*(rx_skb->data + i) != (u8) (i & 0xff)) | ||
7681 | goto out; | ||
7682 | } | ||
7683 | err = 0; | ||
7684 | |||
7685 | /* tg3_free_rings will unmap and free the rx_skb */ | ||
7686 | out: | ||
7687 | return err; | ||
7688 | } | ||
7689 | |||
7579 | static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, | 7690 | static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, |
7580 | u64 *data) | 7691 | u64 *data) |
7581 | { | 7692 | { |
@@ -7613,6 +7724,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, | |||
7613 | etest->flags |= ETH_TEST_FL_FAILED; | 7724 | etest->flags |= ETH_TEST_FL_FAILED; |
7614 | data[3] = 1; | 7725 | data[3] = 1; |
7615 | } | 7726 | } |
7727 | if (tg3_test_loopback(tp) != 0) { | ||
7728 | etest->flags |= ETH_TEST_FL_FAILED; | ||
7729 | data[4] = 1; | ||
7730 | } | ||
7616 | 7731 | ||
7617 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); | 7732 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); |
7618 | if (netif_running(dev)) { | 7733 | if (netif_running(dev)) { |