diff options
author | Yitchak Gertner <gertner@broadcom.com> | 2008-06-23 23:35:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-06-23 23:35:51 -0400 |
commit | f3c87cddfe3fa667f31a9c03a2eec0f3ae1b4bb3 (patch) | |
tree | 7a8f1a4dcdf7a140da29d9e8c3c3d4c3b2f12488 /drivers/net/bnx2x_main.c | |
parent | 755735eb3494630800f337eae33b92bab363f112 (diff) |
bnx2x: Enhanced self test
Added registers, memories, loopback, nvram, interrupt and link tests to
the self-test
Signed-off-by: Yitchak Gertner <gertner@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2x_main.c')
-rw-r--r-- | drivers/net/bnx2x_main.c | 496 |
1 files changed, 487 insertions, 9 deletions
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index e97fe8cddac9..e9037131a04e 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c | |||
@@ -8313,10 +8313,17 @@ static int bnx2x_set_tso(struct net_device *dev, u32 data) | |||
8313 | return 0; | 8313 | return 0; |
8314 | } | 8314 | } |
8315 | 8315 | ||
8316 | static struct { | 8316 | static const struct { |
8317 | char string[ETH_GSTRING_LEN]; | 8317 | char string[ETH_GSTRING_LEN]; |
8318 | } bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = { | 8318 | } bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = { |
8319 | { "MC Errors (online)" } | 8319 | { "register_test (offline)" }, |
8320 | { "memory_test (offline)" }, | ||
8321 | { "loopback_test (offline)" }, | ||
8322 | { "nvram_test (online)" }, | ||
8323 | { "interrupt_test (online)" }, | ||
8324 | { "link_test (online)" }, | ||
8325 | { "idle check (online)" }, | ||
8326 | { "MC errors (online)" } | ||
8320 | }; | 8327 | }; |
8321 | 8328 | ||
8322 | static int bnx2x_self_test_count(struct net_device *dev) | 8329 | static int bnx2x_self_test_count(struct net_device *dev) |
@@ -8324,25 +8331,496 @@ static int bnx2x_self_test_count(struct net_device *dev) | |||
8324 | return BNX2X_NUM_TESTS; | 8331 | return BNX2X_NUM_TESTS; |
8325 | } | 8332 | } |
8326 | 8333 | ||
8334 | static int bnx2x_test_registers(struct bnx2x *bp) | ||
8335 | { | ||
8336 | int idx, i, rc = -ENODEV; | ||
8337 | u32 wr_val = 0; | ||
8338 | static const struct { | ||
8339 | u32 offset0; | ||
8340 | u32 offset1; | ||
8341 | u32 mask; | ||
8342 | } reg_tbl[] = { | ||
8343 | /* 0 */ { BRB1_REG_PAUSE_LOW_THRESHOLD_0, 4, 0x000003ff }, | ||
8344 | { DORQ_REG_DB_ADDR0, 4, 0xffffffff }, | ||
8345 | { HC_REG_AGG_INT_0, 4, 0x000003ff }, | ||
8346 | { PBF_REG_MAC_IF0_ENABLE, 4, 0x00000001 }, | ||
8347 | { PBF_REG_P0_INIT_CRD, 4, 0x000007ff }, | ||
8348 | { PRS_REG_CID_PORT_0, 4, 0x00ffffff }, | ||
8349 | { PXP2_REG_PSWRQ_CDU0_L2P, 4, 0x000fffff }, | ||
8350 | { PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR, 8, 0x0003ffff }, | ||
8351 | { PXP2_REG_PSWRQ_TM0_L2P, 4, 0x000fffff }, | ||
8352 | { PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR, 8, 0x0003ffff }, | ||
8353 | /* 10 */ { PXP2_REG_PSWRQ_TSDM0_L2P, 4, 0x000fffff }, | ||
8354 | { QM_REG_CONNNUM_0, 4, 0x000fffff }, | ||
8355 | { TM_REG_LIN0_MAX_ACTIVE_CID, 4, 0x0003ffff }, | ||
8356 | { SRC_REG_KEYRSS0_0, 40, 0xffffffff }, | ||
8357 | { SRC_REG_KEYRSS0_7, 40, 0xffffffff }, | ||
8358 | { XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 }, | ||
8359 | { XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 }, | ||
8360 | { XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff }, | ||
8361 | { NIG_REG_EGRESS_MNG0_FIFO, 20, 0xffffffff }, | ||
8362 | { NIG_REG_LLH0_T_BIT, 4, 0x00000001 }, | ||
8363 | /* 20 */ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 }, | ||
8364 | { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 }, | ||
8365 | { NIG_REG_XCM0_OUT_EN, 4, 0x00000001 }, | ||
8366 | { NIG_REG_BRB0_OUT_EN, 4, 0x00000001 }, | ||
8367 | { NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 }, | ||
8368 | { NIG_REG_LLH0_ACPI_PAT_6_LEN, 68, 0x000000ff }, | ||
8369 | { NIG_REG_LLH0_ACPI_PAT_0_CRC, 68, 0xffffffff }, | ||
8370 | { NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff }, | ||
8371 | { NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff }, | ||
8372 | { NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 }, | ||
8373 | /* 30 */ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff }, | ||
8374 | { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff }, | ||
8375 | { NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff }, | ||
8376 | { NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 }, | ||
8377 | { NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 }, | ||
8378 | { NIG_REG_STATUS_INTERRUPT_PORT0, 4, 0x07ffffff }, | ||
8379 | { NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST, 24, 0x00000001 }, | ||
8380 | { NIG_REG_SERDES0_CTRL_PHY_ADDR, 16, 0x0000001f }, | ||
8381 | |||
8382 | { 0xffffffff, 0, 0x00000000 } | ||
8383 | }; | ||
8384 | |||
8385 | if (!netif_running(bp->dev)) | ||
8386 | return rc; | ||
8387 | |||
8388 | /* Repeat the test twice: | ||
8389 | First by writing 0x00000000, second by writing 0xffffffff */ | ||
8390 | for (idx = 0; idx < 2; idx++) { | ||
8391 | |||
8392 | switch (idx) { | ||
8393 | case 0: | ||
8394 | wr_val = 0; | ||
8395 | break; | ||
8396 | case 1: | ||
8397 | wr_val = 0xffffffff; | ||
8398 | break; | ||
8399 | } | ||
8400 | |||
8401 | for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) { | ||
8402 | u32 offset, mask, save_val, val; | ||
8403 | int port = BP_PORT(bp); | ||
8404 | |||
8405 | offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1; | ||
8406 | mask = reg_tbl[i].mask; | ||
8407 | |||
8408 | save_val = REG_RD(bp, offset); | ||
8409 | |||
8410 | REG_WR(bp, offset, wr_val); | ||
8411 | val = REG_RD(bp, offset); | ||
8412 | |||
8413 | /* Restore the original register's value */ | ||
8414 | REG_WR(bp, offset, save_val); | ||
8415 | |||
8416 | /* verify that value is as expected value */ | ||
8417 | if ((val & mask) != (wr_val & mask)) | ||
8418 | goto test_reg_exit; | ||
8419 | } | ||
8420 | } | ||
8421 | |||
8422 | rc = 0; | ||
8423 | |||
8424 | test_reg_exit: | ||
8425 | return rc; | ||
8426 | } | ||
8427 | |||
8428 | static int bnx2x_test_memory(struct bnx2x *bp) | ||
8429 | { | ||
8430 | int i, j, rc = -ENODEV; | ||
8431 | u32 val; | ||
8432 | static const struct { | ||
8433 | u32 offset; | ||
8434 | int size; | ||
8435 | } mem_tbl[] = { | ||
8436 | { CCM_REG_XX_DESCR_TABLE, CCM_REG_XX_DESCR_TABLE_SIZE }, | ||
8437 | { CFC_REG_ACTIVITY_COUNTER, CFC_REG_ACTIVITY_COUNTER_SIZE }, | ||
8438 | { CFC_REG_LINK_LIST, CFC_REG_LINK_LIST_SIZE }, | ||
8439 | { DMAE_REG_CMD_MEM, DMAE_REG_CMD_MEM_SIZE }, | ||
8440 | { TCM_REG_XX_DESCR_TABLE, TCM_REG_XX_DESCR_TABLE_SIZE }, | ||
8441 | { UCM_REG_XX_DESCR_TABLE, UCM_REG_XX_DESCR_TABLE_SIZE }, | ||
8442 | { XCM_REG_XX_DESCR_TABLE, XCM_REG_XX_DESCR_TABLE_SIZE }, | ||
8443 | |||
8444 | { 0xffffffff, 0 } | ||
8445 | }; | ||
8446 | static const struct { | ||
8447 | char *name; | ||
8448 | u32 offset; | ||
8449 | u32 mask; | ||
8450 | } prty_tbl[] = { | ||
8451 | { "CCM_REG_CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, 0 }, | ||
8452 | { "CFC_REG_CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, 0 }, | ||
8453 | { "DMAE_REG_DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0 }, | ||
8454 | { "TCM_REG_TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, 0 }, | ||
8455 | { "UCM_REG_UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, 0 }, | ||
8456 | { "XCM_REG_XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, 0x1 }, | ||
8457 | |||
8458 | { NULL, 0xffffffff, 0 } | ||
8459 | }; | ||
8460 | |||
8461 | if (!netif_running(bp->dev)) | ||
8462 | return rc; | ||
8463 | |||
8464 | /* Go through all the memories */ | ||
8465 | for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) | ||
8466 | for (j = 0; j < mem_tbl[i].size; j++) | ||
8467 | REG_RD(bp, mem_tbl[i].offset + j*4); | ||
8468 | |||
8469 | /* Check the parity status */ | ||
8470 | for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) { | ||
8471 | val = REG_RD(bp, prty_tbl[i].offset); | ||
8472 | if (val & ~(prty_tbl[i].mask)) { | ||
8473 | DP(NETIF_MSG_HW, | ||
8474 | "%s is 0x%x\n", prty_tbl[i].name, val); | ||
8475 | goto test_mem_exit; | ||
8476 | } | ||
8477 | } | ||
8478 | |||
8479 | rc = 0; | ||
8480 | |||
8481 | test_mem_exit: | ||
8482 | return rc; | ||
8483 | } | ||
8484 | |||
8485 | static void bnx2x_netif_start(struct bnx2x *bp) | ||
8486 | { | ||
8487 | int i; | ||
8488 | |||
8489 | if (atomic_dec_and_test(&bp->intr_sem)) { | ||
8490 | if (netif_running(bp->dev)) { | ||
8491 | bnx2x_int_enable(bp); | ||
8492 | for_each_queue(bp, i) | ||
8493 | napi_enable(&bnx2x_fp(bp, i, napi)); | ||
8494 | if (bp->state == BNX2X_STATE_OPEN) | ||
8495 | netif_wake_queue(bp->dev); | ||
8496 | } | ||
8497 | } | ||
8498 | } | ||
8499 | |||
8500 | static void bnx2x_netif_stop(struct bnx2x *bp) | ||
8501 | { | ||
8502 | int i; | ||
8503 | |||
8504 | if (netif_running(bp->dev)) { | ||
8505 | netif_tx_disable(bp->dev); | ||
8506 | bp->dev->trans_start = jiffies; /* prevent tx timeout */ | ||
8507 | for_each_queue(bp, i) | ||
8508 | napi_disable(&bnx2x_fp(bp, i, napi)); | ||
8509 | } | ||
8510 | bnx2x_int_disable_sync(bp); | ||
8511 | } | ||
8512 | |||
8513 | static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up) | ||
8514 | { | ||
8515 | int cnt = 1000; | ||
8516 | |||
8517 | if (link_up) | ||
8518 | while (bnx2x_link_test(bp) && cnt--) | ||
8519 | msleep(10); | ||
8520 | } | ||
8521 | |||
8522 | static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) | ||
8523 | { | ||
8524 | unsigned int pkt_size, num_pkts, i; | ||
8525 | struct sk_buff *skb; | ||
8526 | unsigned char *packet; | ||
8527 | struct bnx2x_fastpath *fp = &bp->fp[0]; | ||
8528 | u16 tx_start_idx, tx_idx; | ||
8529 | u16 rx_start_idx, rx_idx; | ||
8530 | u16 pkt_prod; | ||
8531 | struct sw_tx_bd *tx_buf; | ||
8532 | struct eth_tx_bd *tx_bd; | ||
8533 | dma_addr_t mapping; | ||
8534 | union eth_rx_cqe *cqe; | ||
8535 | u8 cqe_fp_flags; | ||
8536 | struct sw_rx_bd *rx_buf; | ||
8537 | u16 len; | ||
8538 | int rc = -ENODEV; | ||
8539 | |||
8540 | if (loopback_mode == BNX2X_MAC_LOOPBACK) { | ||
8541 | bp->link_params.loopback_mode = LOOPBACK_BMAC; | ||
8542 | bnx2x_phy_hw_lock(bp); | ||
8543 | bnx2x_phy_init(&bp->link_params, &bp->link_vars); | ||
8544 | bnx2x_phy_hw_unlock(bp); | ||
8545 | |||
8546 | } else if (loopback_mode == BNX2X_PHY_LOOPBACK) { | ||
8547 | bp->link_params.loopback_mode = LOOPBACK_XGXS_10; | ||
8548 | bnx2x_phy_hw_lock(bp); | ||
8549 | bnx2x_phy_init(&bp->link_params, &bp->link_vars); | ||
8550 | bnx2x_phy_hw_unlock(bp); | ||
8551 | /* wait until link state is restored */ | ||
8552 | bnx2x_wait_for_link(bp, link_up); | ||
8553 | |||
8554 | } else | ||
8555 | return -EINVAL; | ||
8556 | |||
8557 | pkt_size = 1514; | ||
8558 | skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); | ||
8559 | if (!skb) { | ||
8560 | rc = -ENOMEM; | ||
8561 | goto test_loopback_exit; | ||
8562 | } | ||
8563 | packet = skb_put(skb, pkt_size); | ||
8564 | memcpy(packet, bp->dev->dev_addr, ETH_ALEN); | ||
8565 | memset(packet + ETH_ALEN, 0, (ETH_HLEN - ETH_ALEN)); | ||
8566 | for (i = ETH_HLEN; i < pkt_size; i++) | ||
8567 | packet[i] = (unsigned char) (i & 0xff); | ||
8568 | |||
8569 | num_pkts = 0; | ||
8570 | tx_start_idx = le16_to_cpu(*fp->tx_cons_sb); | ||
8571 | rx_start_idx = le16_to_cpu(*fp->rx_cons_sb); | ||
8572 | |||
8573 | pkt_prod = fp->tx_pkt_prod++; | ||
8574 | tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)]; | ||
8575 | tx_buf->first_bd = fp->tx_bd_prod; | ||
8576 | tx_buf->skb = skb; | ||
8577 | |||
8578 | tx_bd = &fp->tx_desc_ring[TX_BD(fp->tx_bd_prod)]; | ||
8579 | mapping = pci_map_single(bp->pdev, skb->data, | ||
8580 | skb_headlen(skb), PCI_DMA_TODEVICE); | ||
8581 | tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); | ||
8582 | tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); | ||
8583 | tx_bd->nbd = cpu_to_le16(1); | ||
8584 | tx_bd->nbytes = cpu_to_le16(skb_headlen(skb)); | ||
8585 | tx_bd->vlan = cpu_to_le16(pkt_prod); | ||
8586 | tx_bd->bd_flags.as_bitfield = (ETH_TX_BD_FLAGS_START_BD | | ||
8587 | ETH_TX_BD_FLAGS_END_BD); | ||
8588 | tx_bd->general_data = ((UNICAST_ADDRESS << | ||
8589 | ETH_TX_BD_ETH_ADDR_TYPE_SHIFT) | 1); | ||
8590 | |||
8591 | fp->hw_tx_prods->bds_prod = | ||
8592 | cpu_to_le16(le16_to_cpu(fp->hw_tx_prods->bds_prod) + 1); | ||
8593 | mb(); /* FW restriction: must not reorder writing nbd and packets */ | ||
8594 | fp->hw_tx_prods->packets_prod = | ||
8595 | cpu_to_le32(le32_to_cpu(fp->hw_tx_prods->packets_prod) + 1); | ||
8596 | DOORBELL(bp, FP_IDX(fp), 0); | ||
8597 | |||
8598 | mmiowb(); | ||
8599 | |||
8600 | num_pkts++; | ||
8601 | fp->tx_bd_prod++; | ||
8602 | bp->dev->trans_start = jiffies; | ||
8603 | |||
8604 | udelay(100); | ||
8605 | |||
8606 | tx_idx = le16_to_cpu(*fp->tx_cons_sb); | ||
8607 | if (tx_idx != tx_start_idx + num_pkts) | ||
8608 | goto test_loopback_exit; | ||
8609 | |||
8610 | rx_idx = le16_to_cpu(*fp->rx_cons_sb); | ||
8611 | if (rx_idx != rx_start_idx + num_pkts) | ||
8612 | goto test_loopback_exit; | ||
8613 | |||
8614 | cqe = &fp->rx_comp_ring[RCQ_BD(fp->rx_comp_cons)]; | ||
8615 | cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; | ||
8616 | if (CQE_TYPE(cqe_fp_flags) || (cqe_fp_flags & ETH_RX_ERROR_FALGS)) | ||
8617 | goto test_loopback_rx_exit; | ||
8618 | |||
8619 | len = le16_to_cpu(cqe->fast_path_cqe.pkt_len); | ||
8620 | if (len != pkt_size) | ||
8621 | goto test_loopback_rx_exit; | ||
8622 | |||
8623 | rx_buf = &fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)]; | ||
8624 | skb = rx_buf->skb; | ||
8625 | skb_reserve(skb, cqe->fast_path_cqe.placement_offset); | ||
8626 | for (i = ETH_HLEN; i < pkt_size; i++) | ||
8627 | if (*(skb->data + i) != (unsigned char) (i & 0xff)) | ||
8628 | goto test_loopback_rx_exit; | ||
8629 | |||
8630 | rc = 0; | ||
8631 | |||
8632 | test_loopback_rx_exit: | ||
8633 | bp->dev->last_rx = jiffies; | ||
8634 | |||
8635 | fp->rx_bd_cons = NEXT_RX_IDX(fp->rx_bd_cons); | ||
8636 | fp->rx_bd_prod = NEXT_RX_IDX(fp->rx_bd_prod); | ||
8637 | fp->rx_comp_cons = NEXT_RCQ_IDX(fp->rx_comp_cons); | ||
8638 | fp->rx_comp_prod = NEXT_RCQ_IDX(fp->rx_comp_prod); | ||
8639 | |||
8640 | /* Update producers */ | ||
8641 | bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, | ||
8642 | fp->rx_sge_prod); | ||
8643 | mmiowb(); /* keep prod updates ordered */ | ||
8644 | |||
8645 | test_loopback_exit: | ||
8646 | bp->link_params.loopback_mode = LOOPBACK_NONE; | ||
8647 | |||
8648 | return rc; | ||
8649 | } | ||
8650 | |||
8651 | static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up) | ||
8652 | { | ||
8653 | int rc = 0; | ||
8654 | |||
8655 | if (!netif_running(bp->dev)) | ||
8656 | return BNX2X_LOOPBACK_FAILED; | ||
8657 | |||
8658 | bnx2x_netif_stop(bp); | ||
8659 | |||
8660 | if (bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up)) { | ||
8661 | DP(NETIF_MSG_PROBE, "MAC loopback failed\n"); | ||
8662 | rc |= BNX2X_MAC_LOOPBACK_FAILED; | ||
8663 | } | ||
8664 | |||
8665 | if (bnx2x_run_loopback(bp, BNX2X_PHY_LOOPBACK, link_up)) { | ||
8666 | DP(NETIF_MSG_PROBE, "PHY loopback failed\n"); | ||
8667 | rc |= BNX2X_PHY_LOOPBACK_FAILED; | ||
8668 | } | ||
8669 | |||
8670 | bnx2x_netif_start(bp); | ||
8671 | |||
8672 | return rc; | ||
8673 | } | ||
8674 | |||
8675 | #define CRC32_RESIDUAL 0xdebb20e3 | ||
8676 | |||
8677 | static int bnx2x_test_nvram(struct bnx2x *bp) | ||
8678 | { | ||
8679 | static const struct { | ||
8680 | int offset; | ||
8681 | int size; | ||
8682 | } nvram_tbl[] = { | ||
8683 | { 0, 0x14 }, /* bootstrap */ | ||
8684 | { 0x14, 0xec }, /* dir */ | ||
8685 | { 0x100, 0x350 }, /* manuf_info */ | ||
8686 | { 0x450, 0xf0 }, /* feature_info */ | ||
8687 | { 0x640, 0x64 }, /* upgrade_key_info */ | ||
8688 | { 0x6a4, 0x64 }, | ||
8689 | { 0x708, 0x70 }, /* manuf_key_info */ | ||
8690 | { 0x778, 0x70 }, | ||
8691 | { 0, 0 } | ||
8692 | }; | ||
8693 | u32 buf[0x350 / 4]; | ||
8694 | u8 *data = (u8 *)buf; | ||
8695 | int i, rc; | ||
8696 | u32 magic, csum; | ||
8697 | |||
8698 | rc = bnx2x_nvram_read(bp, 0, data, 4); | ||
8699 | if (rc) { | ||
8700 | DP(NETIF_MSG_PROBE, "magic value read (rc -%d)\n", -rc); | ||
8701 | goto test_nvram_exit; | ||
8702 | } | ||
8703 | |||
8704 | magic = be32_to_cpu(buf[0]); | ||
8705 | if (magic != 0x669955aa) { | ||
8706 | DP(NETIF_MSG_PROBE, "magic value (0x%08x)\n", magic); | ||
8707 | rc = -ENODEV; | ||
8708 | goto test_nvram_exit; | ||
8709 | } | ||
8710 | |||
8711 | for (i = 0; nvram_tbl[i].size; i++) { | ||
8712 | |||
8713 | rc = bnx2x_nvram_read(bp, nvram_tbl[i].offset, data, | ||
8714 | nvram_tbl[i].size); | ||
8715 | if (rc) { | ||
8716 | DP(NETIF_MSG_PROBE, | ||
8717 | "nvram_tbl[%d] read data (rc -%d)\n", i, -rc); | ||
8718 | goto test_nvram_exit; | ||
8719 | } | ||
8720 | |||
8721 | csum = ether_crc_le(nvram_tbl[i].size, data); | ||
8722 | if (csum != CRC32_RESIDUAL) { | ||
8723 | DP(NETIF_MSG_PROBE, | ||
8724 | "nvram_tbl[%d] csum value (0x%08x)\n", i, csum); | ||
8725 | rc = -ENODEV; | ||
8726 | goto test_nvram_exit; | ||
8727 | } | ||
8728 | } | ||
8729 | |||
8730 | test_nvram_exit: | ||
8731 | return rc; | ||
8732 | } | ||
8733 | |||
8734 | static int bnx2x_test_intr(struct bnx2x *bp) | ||
8735 | { | ||
8736 | struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config); | ||
8737 | int i, rc; | ||
8738 | |||
8739 | if (!netif_running(bp->dev)) | ||
8740 | return -ENODEV; | ||
8741 | |||
8742 | config->hdr.length_6b = 0; | ||
8743 | config->hdr.offset = 0; | ||
8744 | config->hdr.client_id = BP_CL_ID(bp); | ||
8745 | config->hdr.reserved1 = 0; | ||
8746 | |||
8747 | rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, | ||
8748 | U64_HI(bnx2x_sp_mapping(bp, mac_config)), | ||
8749 | U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0); | ||
8750 | if (rc == 0) { | ||
8751 | bp->set_mac_pending++; | ||
8752 | for (i = 0; i < 10; i++) { | ||
8753 | if (!bp->set_mac_pending) | ||
8754 | break; | ||
8755 | msleep_interruptible(10); | ||
8756 | } | ||
8757 | if (i == 10) | ||
8758 | rc = -ENODEV; | ||
8759 | } | ||
8760 | |||
8761 | return rc; | ||
8762 | } | ||
8763 | |||
8327 | static void bnx2x_self_test(struct net_device *dev, | 8764 | static void bnx2x_self_test(struct net_device *dev, |
8328 | struct ethtool_test *etest, u64 *buf) | 8765 | struct ethtool_test *etest, u64 *buf) |
8329 | { | 8766 | { |
8330 | struct bnx2x *bp = netdev_priv(dev); | 8767 | struct bnx2x *bp = netdev_priv(dev); |
8331 | int stats_state; | ||
8332 | 8768 | ||
8333 | memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS); | 8769 | memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS); |
8334 | 8770 | ||
8335 | if (bp->state != BNX2X_STATE_OPEN) { | 8771 | if (!netif_running(dev)) |
8336 | DP(NETIF_MSG_PROBE, "state is %x, returning\n", bp->state); | ||
8337 | return; | 8772 | return; |
8338 | } | ||
8339 | 8773 | ||
8340 | stats_state = bp->stats_state; | 8774 | /* offline tests are not suppoerted in MF mode */ |
8775 | if (IS_E1HMF(bp)) | ||
8776 | etest->flags &= ~ETH_TEST_FL_OFFLINE; | ||
8777 | |||
8778 | if (etest->flags & ETH_TEST_FL_OFFLINE) { | ||
8779 | u8 link_up; | ||
8780 | |||
8781 | link_up = bp->link_vars.link_up; | ||
8782 | bnx2x_nic_unload(bp, UNLOAD_NORMAL); | ||
8783 | bnx2x_nic_load(bp, LOAD_DIAG); | ||
8784 | /* wait until link state is restored */ | ||
8785 | bnx2x_wait_for_link(bp, link_up); | ||
8786 | |||
8787 | if (bnx2x_test_registers(bp) != 0) { | ||
8788 | buf[0] = 1; | ||
8789 | etest->flags |= ETH_TEST_FL_FAILED; | ||
8790 | } | ||
8791 | if (bnx2x_test_memory(bp) != 0) { | ||
8792 | buf[1] = 1; | ||
8793 | etest->flags |= ETH_TEST_FL_FAILED; | ||
8794 | } | ||
8795 | buf[2] = bnx2x_test_loopback(bp, link_up); | ||
8796 | if (buf[2] != 0) | ||
8797 | etest->flags |= ETH_TEST_FL_FAILED; | ||
8341 | 8798 | ||
8342 | if (bnx2x_mc_assert(bp) != 0) { | 8799 | bnx2x_nic_unload(bp, UNLOAD_NORMAL); |
8343 | buf[0] = 1; | 8800 | bnx2x_nic_load(bp, LOAD_NORMAL); |
8801 | /* wait until link state is restored */ | ||
8802 | bnx2x_wait_for_link(bp, link_up); | ||
8803 | } | ||
8804 | if (bnx2x_test_nvram(bp) != 0) { | ||
8805 | buf[3] = 1; | ||
8806 | etest->flags |= ETH_TEST_FL_FAILED; | ||
8807 | } | ||
8808 | if (bnx2x_test_intr(bp) != 0) { | ||
8809 | buf[4] = 1; | ||
8344 | etest->flags |= ETH_TEST_FL_FAILED; | 8810 | etest->flags |= ETH_TEST_FL_FAILED; |
8345 | } | 8811 | } |
8812 | if (bp->port.pmf) | ||
8813 | if (bnx2x_link_test(bp) != 0) { | ||
8814 | buf[5] = 1; | ||
8815 | etest->flags |= ETH_TEST_FL_FAILED; | ||
8816 | } | ||
8817 | buf[7] = bnx2x_mc_assert(bp); | ||
8818 | if (buf[7] != 0) | ||
8819 | etest->flags |= ETH_TEST_FL_FAILED; | ||
8820 | |||
8821 | #ifdef BNX2X_EXTRA_DEBUG | ||
8822 | bnx2x_panic_dump(bp); | ||
8823 | #endif | ||
8346 | } | 8824 | } |
8347 | 8825 | ||
8348 | static const struct { | 8826 | static const struct { |