Loading drivers/net/tg3.c +556 −15 Original line number Diff line number Diff line Loading @@ -133,6 +133,8 @@ /* number of ETHTOOL_GSTATS u64's */ #define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) #define TG3_NUM_TEST 6 static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; Loading Loading @@ -316,6 +318,17 @@ static struct { { "nic_tx_threshold_hit" } }; static struct { const char string[ETH_GSTRING_LEN]; } ethtool_test_keys[TG3_NUM_TEST] = { { "nvram test (online) " }, { "link test (online) " }, { "register test (offline)" }, { "memory test (offline)" }, { "loopback test (offline)" }, { "interrupt test (offline)" }, }; static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) { if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) { Loading Loading @@ -3070,7 +3083,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id, } static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *, int); static int tg3_halt(struct tg3 *, int, int); #ifdef CONFIG_NET_POLL_CONTROLLER static void tg3_poll_controller(struct net_device *dev) Loading @@ -3094,7 +3107,7 @@ static void tg3_reset_task(void *_data) restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; tg3_halt(tp, 0); tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); tg3_init_hw(tp); tg3_netif_start(tp); Loading Loading @@ -3440,7 +3453,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_set_mtu(dev, tp, new_mtu); Loading Loading @@ -4131,19 +4144,19 @@ static void tg3_stop_fw(struct tg3 *tp) } /* tp->lock is held. */ static int tg3_halt(struct tg3 *tp, int silent) static int tg3_halt(struct tg3 *tp, int kind, int silent) { int err; tg3_stop_fw(tp); tg3_write_sig_pre_reset(tp, RESET_KIND_SHUTDOWN); tg3_write_sig_pre_reset(tp, kind); tg3_abort_hw(tp, silent); err = tg3_chip_reset(tp); tg3_write_sig_legacy(tp, RESET_KIND_SHUTDOWN); tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); tg3_write_sig_legacy(tp, kind); tg3_write_sig_post_reset(tp, kind); if (err) return err; Loading Loading @@ -4357,7 +4370,12 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b */ tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; /* It is possible that bootcode is still loading at this point. * Get the nvram lock first before halting the cpu. */ tg3_nvram_lock(tp); err = tg3_halt_cpu(tp, cpu_base); tg3_nvram_unlock(tp); if (err) goto out; Loading Loading @@ -5881,6 +5899,9 @@ static int tg3_test_interrupt(struct tg3 *tp) int err, i; u32 int_mbox = 0; if (!netif_running(dev)) return -ENODEV; tg3_disable_ints(tp); free_irq(tp->pdev->irq, dev); Loading Loading @@ -5984,7 +6005,7 @@ static int tg3_test_msi(struct tg3 *tp) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); err = tg3_init_hw(tp); spin_unlock(&tp->tx_lock); Loading Loading @@ -6060,7 +6081,7 @@ static int tg3_open(struct net_device *dev) err = tg3_init_hw(tp); if (err) { tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); } else { if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) Loading Loading @@ -6104,7 +6125,7 @@ static int tg3_open(struct net_device *dev) pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; } tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); tg3_free_consistent(tp); Loading Loading @@ -6377,7 +6398,7 @@ static int tg3_close(struct net_device *dev) tg3_disable_ints(tp); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); tp->tg3_flags &= ~(TG3_FLAG_INIT_COMPLETE | Loading Loading @@ -7097,7 +7118,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tp->tx_pending = ering->tx_pending; if (netif_running(dev)) { tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_init_hw(tp); tg3_netif_start(tp); } Loading Loading @@ -7140,7 +7161,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE; if (netif_running(dev)) { tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_init_hw(tp); tg3_netif_start(tp); } Loading Loading @@ -7199,12 +7220,20 @@ static int tg3_get_stats_count (struct net_device *dev) return TG3_NUM_STATS; } static int tg3_get_test_count (struct net_device *dev) { return TG3_NUM_TEST; } static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf) { switch (stringset) { case ETH_SS_STATS: memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); break; case ETH_SS_TEST: memcpy(buf, ðtool_test_keys, sizeof(ethtool_test_keys)); break; default: WARN_ON(1); /* we need a WARN() */ break; Loading @@ -7218,6 +7247,516 @@ static void tg3_get_ethtool_stats (struct net_device *dev, memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats)); } #define NVRAM_TEST_SIZE 0x100 static int tg3_test_nvram(struct tg3 *tp) { u32 *buf, csum; int i, j, err = 0; buf = kmalloc(NVRAM_TEST_SIZE, GFP_KERNEL); if (buf == NULL) return -ENOMEM; for (i = 0, j = 0; i < NVRAM_TEST_SIZE; i += 4, j++) { u32 val; if ((err = tg3_nvram_read(tp, i, &val)) != 0) break; buf[j] = cpu_to_le32(val); } if (i < NVRAM_TEST_SIZE) goto out; err = -EIO; if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) goto out; /* Bootstrap checksum at offset 0x10 */ csum = calc_crc((unsigned char *) buf, 0x10); if(csum != cpu_to_le32(buf[0x10/4])) goto out; /* Manufacturing block starts at offset 0x74, checksum at 0xfc */ csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88); if (csum != cpu_to_le32(buf[0xfc/4])) goto out; err = 0; out: kfree(buf); return err; } #define TG3_SERDES_TIMEOUT_SEC 2 #define TG3_COPPER_TIMEOUT_SEC 6 static int tg3_test_link(struct tg3 *tp) { int i, max; if (!netif_running(tp->dev)) return -ENODEV; if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) max = TG3_SERDES_TIMEOUT_SEC; else max = TG3_COPPER_TIMEOUT_SEC; for (i = 0; i < max; i++) { if (netif_carrier_ok(tp->dev)) return 0; if (msleep_interruptible(1000)) break; } return -EIO; } /* Only test the commonly used registers */ static int tg3_test_registers(struct tg3 *tp) { int i, is_5705; u32 offset, read_mask, write_mask, val, save_val, read_val; static struct { u16 offset; u16 flags; #define TG3_FL_5705 0x1 #define TG3_FL_NOT_5705 0x2 #define TG3_FL_NOT_5788 0x4 u32 read_mask; u32 write_mask; } reg_tbl[] = { /* MAC Control Registers */ { MAC_MODE, TG3_FL_NOT_5705, 0x00000000, 0x00ef6f8c }, { MAC_MODE, TG3_FL_5705, 0x00000000, 0x01ef6b8c }, { MAC_STATUS, TG3_FL_NOT_5705, 0x03800107, 0x00000000 }, { MAC_STATUS, TG3_FL_5705, 0x03800100, 0x00000000 }, { MAC_ADDR_0_HIGH, 0x0000, 0x00000000, 0x0000ffff }, { MAC_ADDR_0_LOW, 0x0000, 0x00000000, 0xffffffff }, { MAC_RX_MTU_SIZE, 0x0000, 0x00000000, 0x0000ffff }, { MAC_TX_MODE, 0x0000, 0x00000000, 0x00000070 }, { MAC_TX_LENGTHS, 0x0000, 0x00000000, 0x00003fff }, { MAC_RX_MODE, TG3_FL_NOT_5705, 0x00000000, 0x000007fc }, { MAC_RX_MODE, TG3_FL_5705, 0x00000000, 0x000007dc }, { MAC_HASH_REG_0, 0x0000, 0x00000000, 0xffffffff }, { MAC_HASH_REG_1, 0x0000, 0x00000000, 0xffffffff }, { MAC_HASH_REG_2, 0x0000, 0x00000000, 0xffffffff }, { MAC_HASH_REG_3, 0x0000, 0x00000000, 0xffffffff }, /* Receive Data and Receive BD Initiator Control Registers. */ { RCVDBDI_JUMBO_BD+0, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { RCVDBDI_JUMBO_BD+4, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { RCVDBDI_JUMBO_BD+8, TG3_FL_NOT_5705, 0x00000000, 0x00000003 }, { RCVDBDI_JUMBO_BD+0xc, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { RCVDBDI_STD_BD+0, 0x0000, 0x00000000, 0xffffffff }, { RCVDBDI_STD_BD+4, 0x0000, 0x00000000, 0xffffffff }, { RCVDBDI_STD_BD+8, 0x0000, 0x00000000, 0xffff0002 }, { RCVDBDI_STD_BD+0xc, 0x0000, 0x00000000, 0xffffffff }, /* Receive BD Initiator Control Registers. */ { RCVBDI_STD_THRESH, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { RCVBDI_STD_THRESH, TG3_FL_5705, 0x00000000, 0x000003ff }, { RCVBDI_JUMBO_THRESH, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, /* Host Coalescing Control Registers. */ { HOSTCC_MODE, TG3_FL_NOT_5705, 0x00000000, 0x00000004 }, { HOSTCC_MODE, TG3_FL_5705, 0x00000000, 0x000000f6 }, { HOSTCC_RXCOL_TICKS, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_RXCOL_TICKS, TG3_FL_5705, 0x00000000, 0x000003ff }, { HOSTCC_TXCOL_TICKS, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_TXCOL_TICKS, TG3_FL_5705, 0x00000000, 0x000003ff }, { HOSTCC_RXMAX_FRAMES, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_RXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788, 0x00000000, 0x000000ff }, { HOSTCC_TXMAX_FRAMES, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_TXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788, 0x00000000, 0x000000ff }, { HOSTCC_RXCOAL_TICK_INT, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_TXCOAL_TICK_INT, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_RXCOAL_MAXF_INT, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_RXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788, 0x00000000, 0x000000ff }, { HOSTCC_TXCOAL_MAXF_INT, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_TXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788, 0x00000000, 0x000000ff }, { HOSTCC_STAT_COAL_TICKS, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_STATS_BLK_HOST_ADDR, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_STATS_BLK_HOST_ADDR+4, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_STATUS_BLK_HOST_ADDR, 0x0000, 0x00000000, 0xffffffff }, { HOSTCC_STATUS_BLK_HOST_ADDR+4, 0x0000, 0x00000000, 0xffffffff }, { HOSTCC_STATS_BLK_NIC_ADDR, 0x0000, 0xffffffff, 0x00000000 }, { HOSTCC_STATUS_BLK_NIC_ADDR, 0x0000, 0xffffffff, 0x00000000 }, /* Buffer Manager Control Registers. */ { BUFMGR_MB_POOL_ADDR, 0x0000, 0x00000000, 0x007fff80 }, { BUFMGR_MB_POOL_SIZE, 0x0000, 0x00000000, 0x007fffff }, { BUFMGR_MB_RDMA_LOW_WATER, 0x0000, 0x00000000, 0x0000003f }, { BUFMGR_MB_MACRX_LOW_WATER, 0x0000, 0x00000000, 0x000001ff }, { BUFMGR_MB_HIGH_WATER, 0x0000, 0x00000000, 0x000001ff }, { BUFMGR_DMA_DESC_POOL_ADDR, TG3_FL_NOT_5705, 0xffffffff, 0x00000000 }, { BUFMGR_DMA_DESC_POOL_SIZE, TG3_FL_NOT_5705, 0xffffffff, 0x00000000 }, /* Mailbox Registers */ { GRCMBOX_RCVSTD_PROD_IDX+4, 0x0000, 0x00000000, 0x000001ff }, { GRCMBOX_RCVJUMBO_PROD_IDX+4, TG3_FL_NOT_5705, 0x00000000, 0x000001ff }, { GRCMBOX_RCVRET_CON_IDX_0+4, 0x0000, 0x00000000, 0x000007ff }, { GRCMBOX_SNDHOST_PROD_IDX_0+4, 0x0000, 0x00000000, 0x000001ff }, { 0xffff, 0x0000, 0x00000000, 0x00000000 }, }; if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) is_5705 = 1; else is_5705 = 0; for (i = 0; reg_tbl[i].offset != 0xffff; i++) { if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705)) continue; if (!is_5705 && (reg_tbl[i].flags & TG3_FL_5705)) continue; if ((tp->tg3_flags2 & TG3_FLG2_IS_5788) && (reg_tbl[i].flags & TG3_FL_NOT_5788)) continue; offset = (u32) reg_tbl[i].offset; read_mask = reg_tbl[i].read_mask; write_mask = reg_tbl[i].write_mask; /* Save the original register content */ save_val = tr32(offset); /* Determine the read-only value. */ read_val = save_val & read_mask; /* Write zero to the register, then make sure the read-only bits * are not changed and the read/write bits are all zeros. */ tw32(offset, 0); val = tr32(offset); /* Test the read-only and read/write bits. */ if (((val & read_mask) != read_val) || (val & write_mask)) goto out; /* Write ones to all the bits defined by RdMask and WrMask, then * make sure the read-only bits are not changed and the * read/write bits are all ones. */ tw32(offset, read_mask | write_mask); val = tr32(offset); /* Test the read-only bits. */ if ((val & read_mask) != read_val) goto out; /* Test the read/write bits. */ if ((val & write_mask) != write_mask) goto out; tw32(offset, save_val); } return 0; out: printk(KERN_ERR PFX "Register test failed at offset %x\n", offset); tw32(offset, save_val); return -EIO; } static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len) { static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0xaa55a55a }; int i; u32 j; for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) { for (j = 0; j < len; j += 4) { u32 val; tg3_write_mem(tp, offset + j, test_pattern[i]); tg3_read_mem(tp, offset + j, &val); if (val != test_pattern[i]) return -EIO; } } return 0; } static int tg3_test_memory(struct tg3 *tp) { static struct mem_entry { u32 offset; u32 len; } mem_tbl_570x[] = { { 0x00000000, 0x01000}, { 0x00002000, 0x1c000}, { 0xffffffff, 0x00000} }, mem_tbl_5705[] = { { 0x00000100, 0x0000c}, { 0x00000200, 0x00008}, { 0x00000b50, 0x00400}, { 0x00004000, 0x00800}, { 0x00006000, 0x01000}, { 0x00008000, 0x02000}, { 0x00010000, 0x0e000}, { 0xffffffff, 0x00000} }; struct mem_entry *mem_tbl; int err = 0; int i; if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) mem_tbl = mem_tbl_5705; else mem_tbl = mem_tbl_570x; for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) { if ((err = tg3_do_mem_test(tp, mem_tbl[i].offset, mem_tbl[i].len)) != 0) break; } return err; } static int tg3_test_loopback(struct tg3 *tp) { u32 mac_mode, send_idx, rx_start_idx, rx_idx, tx_idx, opaque_key; u32 desc_idx; struct sk_buff *skb, *rx_skb; u8 *tx_data; dma_addr_t map; int num_pkts, tx_len, rx_len, i, err; struct tg3_rx_buffer_desc *desc; if (!netif_running(tp->dev)) return -ENODEV; err = -EIO; tg3_abort_hw(tp, 1); /* Clearing this flag to keep interrupts disabled */ tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; tg3_reset_hw(tp); mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII; tw32(MAC_MODE, mac_mode); tx_len = 1514; skb = dev_alloc_skb(tx_len); tx_data = skb_put(skb, tx_len); memcpy(tx_data, tp->dev->dev_addr, 6); memset(tx_data + 6, 0x0, 8); tw32(MAC_RX_MTU_SIZE, tx_len + 4); for (i = 14; i < tx_len; i++) tx_data[i] = (u8) (i & 0xff); map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW); udelay(10); rx_start_idx = tp->hw_status->idx[0].rx_producer; send_idx = 0; num_pkts = 0; tg3_set_txd(tp, send_idx, map, tx_len, 0, 1); send_idx++; num_pkts++; tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, send_idx); tr32(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW); udelay(10); for (i = 0; i < 10; i++) { tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW); udelay(10); tx_idx = tp->hw_status->idx[0].tx_consumer; rx_idx = tp->hw_status->idx[0].rx_producer; if ((tx_idx == send_idx) && (rx_idx == (rx_start_idx + num_pkts))) break; } pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); if (tx_idx != send_idx) goto out; if (rx_idx != rx_start_idx + num_pkts) goto out; desc = &tp->rx_rcb[rx_start_idx]; desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; if (opaque_key != RXD_OPAQUE_RING_STD) goto out; if ((desc->err_vlan & RXD_ERR_MASK) != 0 && (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) goto out; rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; if (rx_len != tx_len) goto out; rx_skb = tp->rx_std_buffers[desc_idx].skb; map = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], mapping); pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); for (i = 14; i < tx_len; i++) { if (*(rx_skb->data + i) != (u8) (i & 0xff)) goto out; } err = 0; /* tg3_free_rings will unmap and free the rx_skb */ out: return err; } static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *data) { struct tg3 *tp = netdev_priv(dev); memset(data, 0, sizeof(u64) * TG3_NUM_TEST); if (tg3_test_nvram(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[0] = 1; } if (tg3_test_link(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[1] = 1; } if (etest->flags & ETH_TEST_FL_OFFLINE) { if (netif_running(dev)) tg3_netif_stop(tp); spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, RESET_KIND_SUSPEND, 1); tg3_nvram_lock(tp); tg3_halt_cpu(tp, RX_CPU_BASE); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) tg3_halt_cpu(tp, TX_CPU_BASE); tg3_nvram_unlock(tp); if (tg3_test_registers(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[2] = 1; } if (tg3_test_memory(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[3] = 1; } if (tg3_test_loopback(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[4] = 1; } spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); if (tg3_test_interrupt(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[5] = 1; } spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; tg3_init_hw(tp); tg3_netif_start(tp); } spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); } } static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = if_mii(ifr); Loading Loading @@ -7331,6 +7870,8 @@ static struct ethtool_ops tg3_ethtool_ops = { .get_tso = ethtool_op_get_tso, .set_tso = tg3_set_tso, #endif .self_test_count = tg3_get_test_count, .self_test = tg3_self_test, .get_strings = tg3_get_strings, .get_stats_count = tg3_get_stats_count, .get_ethtool_stats = tg3_get_ethtool_stats, Loading Loading @@ -9478,7 +10019,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { pci_save_state(tp->pdev); tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); } err = tg3_test_dma(tp); Loading Loading @@ -9605,7 +10146,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); Loading Loading
drivers/net/tg3.c +556 −15 Original line number Diff line number Diff line Loading @@ -133,6 +133,8 @@ /* number of ETHTOOL_GSTATS u64's */ #define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) #define TG3_NUM_TEST 6 static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; Loading Loading @@ -316,6 +318,17 @@ static struct { { "nic_tx_threshold_hit" } }; static struct { const char string[ETH_GSTRING_LEN]; } ethtool_test_keys[TG3_NUM_TEST] = { { "nvram test (online) " }, { "link test (online) " }, { "register test (offline)" }, { "memory test (offline)" }, { "loopback test (offline)" }, { "interrupt test (offline)" }, }; static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) { if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) { Loading Loading @@ -3070,7 +3083,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id, } static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *, int); static int tg3_halt(struct tg3 *, int, int); #ifdef CONFIG_NET_POLL_CONTROLLER static void tg3_poll_controller(struct net_device *dev) Loading @@ -3094,7 +3107,7 @@ static void tg3_reset_task(void *_data) restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; tg3_halt(tp, 0); tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); tg3_init_hw(tp); tg3_netif_start(tp); Loading Loading @@ -3440,7 +3453,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_set_mtu(dev, tp, new_mtu); Loading Loading @@ -4131,19 +4144,19 @@ static void tg3_stop_fw(struct tg3 *tp) } /* tp->lock is held. */ static int tg3_halt(struct tg3 *tp, int silent) static int tg3_halt(struct tg3 *tp, int kind, int silent) { int err; tg3_stop_fw(tp); tg3_write_sig_pre_reset(tp, RESET_KIND_SHUTDOWN); tg3_write_sig_pre_reset(tp, kind); tg3_abort_hw(tp, silent); err = tg3_chip_reset(tp); tg3_write_sig_legacy(tp, RESET_KIND_SHUTDOWN); tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); tg3_write_sig_legacy(tp, kind); tg3_write_sig_post_reset(tp, kind); if (err) return err; Loading Loading @@ -4357,7 +4370,12 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b */ tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; /* It is possible that bootcode is still loading at this point. * Get the nvram lock first before halting the cpu. */ tg3_nvram_lock(tp); err = tg3_halt_cpu(tp, cpu_base); tg3_nvram_unlock(tp); if (err) goto out; Loading Loading @@ -5881,6 +5899,9 @@ static int tg3_test_interrupt(struct tg3 *tp) int err, i; u32 int_mbox = 0; if (!netif_running(dev)) return -ENODEV; tg3_disable_ints(tp); free_irq(tp->pdev->irq, dev); Loading Loading @@ -5984,7 +6005,7 @@ static int tg3_test_msi(struct tg3 *tp) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); err = tg3_init_hw(tp); spin_unlock(&tp->tx_lock); Loading Loading @@ -6060,7 +6081,7 @@ static int tg3_open(struct net_device *dev) err = tg3_init_hw(tp); if (err) { tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); } else { if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) Loading Loading @@ -6104,7 +6125,7 @@ static int tg3_open(struct net_device *dev) pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; } tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); tg3_free_consistent(tp); Loading Loading @@ -6377,7 +6398,7 @@ static int tg3_close(struct net_device *dev) tg3_disable_ints(tp); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); tp->tg3_flags &= ~(TG3_FLAG_INIT_COMPLETE | Loading Loading @@ -7097,7 +7118,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tp->tx_pending = ering->tx_pending; if (netif_running(dev)) { tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_init_hw(tp); tg3_netif_start(tp); } Loading Loading @@ -7140,7 +7161,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE; if (netif_running(dev)) { tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_init_hw(tp); tg3_netif_start(tp); } Loading Loading @@ -7199,12 +7220,20 @@ static int tg3_get_stats_count (struct net_device *dev) return TG3_NUM_STATS; } static int tg3_get_test_count (struct net_device *dev) { return TG3_NUM_TEST; } static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf) { switch (stringset) { case ETH_SS_STATS: memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); break; case ETH_SS_TEST: memcpy(buf, ðtool_test_keys, sizeof(ethtool_test_keys)); break; default: WARN_ON(1); /* we need a WARN() */ break; Loading @@ -7218,6 +7247,516 @@ static void tg3_get_ethtool_stats (struct net_device *dev, memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats)); } #define NVRAM_TEST_SIZE 0x100 static int tg3_test_nvram(struct tg3 *tp) { u32 *buf, csum; int i, j, err = 0; buf = kmalloc(NVRAM_TEST_SIZE, GFP_KERNEL); if (buf == NULL) return -ENOMEM; for (i = 0, j = 0; i < NVRAM_TEST_SIZE; i += 4, j++) { u32 val; if ((err = tg3_nvram_read(tp, i, &val)) != 0) break; buf[j] = cpu_to_le32(val); } if (i < NVRAM_TEST_SIZE) goto out; err = -EIO; if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) goto out; /* Bootstrap checksum at offset 0x10 */ csum = calc_crc((unsigned char *) buf, 0x10); if(csum != cpu_to_le32(buf[0x10/4])) goto out; /* Manufacturing block starts at offset 0x74, checksum at 0xfc */ csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88); if (csum != cpu_to_le32(buf[0xfc/4])) goto out; err = 0; out: kfree(buf); return err; } #define TG3_SERDES_TIMEOUT_SEC 2 #define TG3_COPPER_TIMEOUT_SEC 6 static int tg3_test_link(struct tg3 *tp) { int i, max; if (!netif_running(tp->dev)) return -ENODEV; if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) max = TG3_SERDES_TIMEOUT_SEC; else max = TG3_COPPER_TIMEOUT_SEC; for (i = 0; i < max; i++) { if (netif_carrier_ok(tp->dev)) return 0; if (msleep_interruptible(1000)) break; } return -EIO; } /* Only test the commonly used registers */ static int tg3_test_registers(struct tg3 *tp) { int i, is_5705; u32 offset, read_mask, write_mask, val, save_val, read_val; static struct { u16 offset; u16 flags; #define TG3_FL_5705 0x1 #define TG3_FL_NOT_5705 0x2 #define TG3_FL_NOT_5788 0x4 u32 read_mask; u32 write_mask; } reg_tbl[] = { /* MAC Control Registers */ { MAC_MODE, TG3_FL_NOT_5705, 0x00000000, 0x00ef6f8c }, { MAC_MODE, TG3_FL_5705, 0x00000000, 0x01ef6b8c }, { MAC_STATUS, TG3_FL_NOT_5705, 0x03800107, 0x00000000 }, { MAC_STATUS, TG3_FL_5705, 0x03800100, 0x00000000 }, { MAC_ADDR_0_HIGH, 0x0000, 0x00000000, 0x0000ffff }, { MAC_ADDR_0_LOW, 0x0000, 0x00000000, 0xffffffff }, { MAC_RX_MTU_SIZE, 0x0000, 0x00000000, 0x0000ffff }, { MAC_TX_MODE, 0x0000, 0x00000000, 0x00000070 }, { MAC_TX_LENGTHS, 0x0000, 0x00000000, 0x00003fff }, { MAC_RX_MODE, TG3_FL_NOT_5705, 0x00000000, 0x000007fc }, { MAC_RX_MODE, TG3_FL_5705, 0x00000000, 0x000007dc }, { MAC_HASH_REG_0, 0x0000, 0x00000000, 0xffffffff }, { MAC_HASH_REG_1, 0x0000, 0x00000000, 0xffffffff }, { MAC_HASH_REG_2, 0x0000, 0x00000000, 0xffffffff }, { MAC_HASH_REG_3, 0x0000, 0x00000000, 0xffffffff }, /* Receive Data and Receive BD Initiator Control Registers. */ { RCVDBDI_JUMBO_BD+0, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { RCVDBDI_JUMBO_BD+4, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { RCVDBDI_JUMBO_BD+8, TG3_FL_NOT_5705, 0x00000000, 0x00000003 }, { RCVDBDI_JUMBO_BD+0xc, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { RCVDBDI_STD_BD+0, 0x0000, 0x00000000, 0xffffffff }, { RCVDBDI_STD_BD+4, 0x0000, 0x00000000, 0xffffffff }, { RCVDBDI_STD_BD+8, 0x0000, 0x00000000, 0xffff0002 }, { RCVDBDI_STD_BD+0xc, 0x0000, 0x00000000, 0xffffffff }, /* Receive BD Initiator Control Registers. */ { RCVBDI_STD_THRESH, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { RCVBDI_STD_THRESH, TG3_FL_5705, 0x00000000, 0x000003ff }, { RCVBDI_JUMBO_THRESH, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, /* Host Coalescing Control Registers. */ { HOSTCC_MODE, TG3_FL_NOT_5705, 0x00000000, 0x00000004 }, { HOSTCC_MODE, TG3_FL_5705, 0x00000000, 0x000000f6 }, { HOSTCC_RXCOL_TICKS, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_RXCOL_TICKS, TG3_FL_5705, 0x00000000, 0x000003ff }, { HOSTCC_TXCOL_TICKS, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_TXCOL_TICKS, TG3_FL_5705, 0x00000000, 0x000003ff }, { HOSTCC_RXMAX_FRAMES, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_RXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788, 0x00000000, 0x000000ff }, { HOSTCC_TXMAX_FRAMES, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_TXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788, 0x00000000, 0x000000ff }, { HOSTCC_RXCOAL_TICK_INT, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_TXCOAL_TICK_INT, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_RXCOAL_MAXF_INT, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_RXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788, 0x00000000, 0x000000ff }, { HOSTCC_TXCOAL_MAXF_INT, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_TXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788, 0x00000000, 0x000000ff }, { HOSTCC_STAT_COAL_TICKS, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_STATS_BLK_HOST_ADDR, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_STATS_BLK_HOST_ADDR+4, TG3_FL_NOT_5705, 0x00000000, 0xffffffff }, { HOSTCC_STATUS_BLK_HOST_ADDR, 0x0000, 0x00000000, 0xffffffff }, { HOSTCC_STATUS_BLK_HOST_ADDR+4, 0x0000, 0x00000000, 0xffffffff }, { HOSTCC_STATS_BLK_NIC_ADDR, 0x0000, 0xffffffff, 0x00000000 }, { HOSTCC_STATUS_BLK_NIC_ADDR, 0x0000, 0xffffffff, 0x00000000 }, /* Buffer Manager Control Registers. */ { BUFMGR_MB_POOL_ADDR, 0x0000, 0x00000000, 0x007fff80 }, { BUFMGR_MB_POOL_SIZE, 0x0000, 0x00000000, 0x007fffff }, { BUFMGR_MB_RDMA_LOW_WATER, 0x0000, 0x00000000, 0x0000003f }, { BUFMGR_MB_MACRX_LOW_WATER, 0x0000, 0x00000000, 0x000001ff }, { BUFMGR_MB_HIGH_WATER, 0x0000, 0x00000000, 0x000001ff }, { BUFMGR_DMA_DESC_POOL_ADDR, TG3_FL_NOT_5705, 0xffffffff, 0x00000000 }, { BUFMGR_DMA_DESC_POOL_SIZE, TG3_FL_NOT_5705, 0xffffffff, 0x00000000 }, /* Mailbox Registers */ { GRCMBOX_RCVSTD_PROD_IDX+4, 0x0000, 0x00000000, 0x000001ff }, { GRCMBOX_RCVJUMBO_PROD_IDX+4, TG3_FL_NOT_5705, 0x00000000, 0x000001ff }, { GRCMBOX_RCVRET_CON_IDX_0+4, 0x0000, 0x00000000, 0x000007ff }, { GRCMBOX_SNDHOST_PROD_IDX_0+4, 0x0000, 0x00000000, 0x000001ff }, { 0xffff, 0x0000, 0x00000000, 0x00000000 }, }; if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) is_5705 = 1; else is_5705 = 0; for (i = 0; reg_tbl[i].offset != 0xffff; i++) { if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705)) continue; if (!is_5705 && (reg_tbl[i].flags & TG3_FL_5705)) continue; if ((tp->tg3_flags2 & TG3_FLG2_IS_5788) && (reg_tbl[i].flags & TG3_FL_NOT_5788)) continue; offset = (u32) reg_tbl[i].offset; read_mask = reg_tbl[i].read_mask; write_mask = reg_tbl[i].write_mask; /* Save the original register content */ save_val = tr32(offset); /* Determine the read-only value. */ read_val = save_val & read_mask; /* Write zero to the register, then make sure the read-only bits * are not changed and the read/write bits are all zeros. */ tw32(offset, 0); val = tr32(offset); /* Test the read-only and read/write bits. */ if (((val & read_mask) != read_val) || (val & write_mask)) goto out; /* Write ones to all the bits defined by RdMask and WrMask, then * make sure the read-only bits are not changed and the * read/write bits are all ones. */ tw32(offset, read_mask | write_mask); val = tr32(offset); /* Test the read-only bits. */ if ((val & read_mask) != read_val) goto out; /* Test the read/write bits. */ if ((val & write_mask) != write_mask) goto out; tw32(offset, save_val); } return 0; out: printk(KERN_ERR PFX "Register test failed at offset %x\n", offset); tw32(offset, save_val); return -EIO; } static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len) { static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0xaa55a55a }; int i; u32 j; for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) { for (j = 0; j < len; j += 4) { u32 val; tg3_write_mem(tp, offset + j, test_pattern[i]); tg3_read_mem(tp, offset + j, &val); if (val != test_pattern[i]) return -EIO; } } return 0; } static int tg3_test_memory(struct tg3 *tp) { static struct mem_entry { u32 offset; u32 len; } mem_tbl_570x[] = { { 0x00000000, 0x01000}, { 0x00002000, 0x1c000}, { 0xffffffff, 0x00000} }, mem_tbl_5705[] = { { 0x00000100, 0x0000c}, { 0x00000200, 0x00008}, { 0x00000b50, 0x00400}, { 0x00004000, 0x00800}, { 0x00006000, 0x01000}, { 0x00008000, 0x02000}, { 0x00010000, 0x0e000}, { 0xffffffff, 0x00000} }; struct mem_entry *mem_tbl; int err = 0; int i; if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) mem_tbl = mem_tbl_5705; else mem_tbl = mem_tbl_570x; for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) { if ((err = tg3_do_mem_test(tp, mem_tbl[i].offset, mem_tbl[i].len)) != 0) break; } return err; } static int tg3_test_loopback(struct tg3 *tp) { u32 mac_mode, send_idx, rx_start_idx, rx_idx, tx_idx, opaque_key; u32 desc_idx; struct sk_buff *skb, *rx_skb; u8 *tx_data; dma_addr_t map; int num_pkts, tx_len, rx_len, i, err; struct tg3_rx_buffer_desc *desc; if (!netif_running(tp->dev)) return -ENODEV; err = -EIO; tg3_abort_hw(tp, 1); /* Clearing this flag to keep interrupts disabled */ tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; tg3_reset_hw(tp); mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII; tw32(MAC_MODE, mac_mode); tx_len = 1514; skb = dev_alloc_skb(tx_len); tx_data = skb_put(skb, tx_len); memcpy(tx_data, tp->dev->dev_addr, 6); memset(tx_data + 6, 0x0, 8); tw32(MAC_RX_MTU_SIZE, tx_len + 4); for (i = 14; i < tx_len; i++) tx_data[i] = (u8) (i & 0xff); map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW); udelay(10); rx_start_idx = tp->hw_status->idx[0].rx_producer; send_idx = 0; num_pkts = 0; tg3_set_txd(tp, send_idx, map, tx_len, 0, 1); send_idx++; num_pkts++; tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, send_idx); tr32(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW); udelay(10); for (i = 0; i < 10; i++) { tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW); udelay(10); tx_idx = tp->hw_status->idx[0].tx_consumer; rx_idx = tp->hw_status->idx[0].rx_producer; if ((tx_idx == send_idx) && (rx_idx == (rx_start_idx + num_pkts))) break; } pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); if (tx_idx != send_idx) goto out; if (rx_idx != rx_start_idx + num_pkts) goto out; desc = &tp->rx_rcb[rx_start_idx]; desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; if (opaque_key != RXD_OPAQUE_RING_STD) goto out; if ((desc->err_vlan & RXD_ERR_MASK) != 0 && (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) goto out; rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; if (rx_len != tx_len) goto out; rx_skb = tp->rx_std_buffers[desc_idx].skb; map = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], mapping); pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); for (i = 14; i < tx_len; i++) { if (*(rx_skb->data + i) != (u8) (i & 0xff)) goto out; } err = 0; /* tg3_free_rings will unmap and free the rx_skb */ out: return err; } static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *data) { struct tg3 *tp = netdev_priv(dev); memset(data, 0, sizeof(u64) * TG3_NUM_TEST); if (tg3_test_nvram(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[0] = 1; } if (tg3_test_link(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[1] = 1; } if (etest->flags & ETH_TEST_FL_OFFLINE) { if (netif_running(dev)) tg3_netif_stop(tp); spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, RESET_KIND_SUSPEND, 1); tg3_nvram_lock(tp); tg3_halt_cpu(tp, RX_CPU_BASE); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) tg3_halt_cpu(tp, TX_CPU_BASE); tg3_nvram_unlock(tp); if (tg3_test_registers(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[2] = 1; } if (tg3_test_memory(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[3] = 1; } if (tg3_test_loopback(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[4] = 1; } spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); if (tg3_test_interrupt(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[5] = 1; } spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; tg3_init_hw(tp); tg3_netif_start(tp); } spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); } } static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = if_mii(ifr); Loading Loading @@ -7331,6 +7870,8 @@ static struct ethtool_ops tg3_ethtool_ops = { .get_tso = ethtool_op_get_tso, .set_tso = tg3_set_tso, #endif .self_test_count = tg3_get_test_count, .self_test = tg3_self_test, .get_strings = tg3_get_strings, .get_stats_count = tg3_get_stats_count, .get_ethtool_stats = tg3_get_ethtool_stats, Loading Loading @@ -9478,7 +10019,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { pci_save_state(tp->pdev); tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); } err = tg3_test_dma(tp); Loading Loading @@ -9605,7 +10146,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); Loading