/** * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines * @dev: atapter's net device data struct * @test_info: array with test request mask also used to store test results * * RETURNS: updated flags field of struct ethtool_test */ u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags) { struct e100_private* bdp = dev->priv; u8 test_result = 0; if (!e100_get_link_state(bdp)) { test_result = ETH_TEST_FL_FAILED; test_info[test_link] = true; } if (!e100_diag_eeprom(dev)) { test_result = ETH_TEST_FL_FAILED; test_info[test_eeprom] = true; } if (flags & ETH_TEST_FL_OFFLINE) { u8 fail_mask; if (netif_running(dev)) { spin_lock_bh(&dev->xmit_lock); e100_close(dev); spin_unlock_bh(&dev->xmit_lock); } if (e100_diag_selftest(dev)) { test_result = ETH_TEST_FL_FAILED; test_info[test_self_test] = true; } fail_mask = e100_diag_loopback(dev); if (fail_mask) { test_result = ETH_TEST_FL_FAILED; if (fail_mask & PHY_LOOPBACK) test_info[test_loopback_phy] = true; if (fail_mask & MAC_LOOPBACK) test_info[test_loopback_mac] = true; } test_info[cable_diag] = e100_cable_diag(bdp); /* Need hw init regardless of netif_running */ e100_hw_init(bdp); if (netif_running(dev)) { e100_open(dev); } } else { test_info[test_self_test] = false; test_info[test_loopback_phy] = false; test_info[test_loopback_mac] = false; test_info[cable_diag] = false; } return flags | test_result; }
/* * Procedure: e100_update_link_state * * Description: This routine updates the link status of the adapter, * also considering netif_running * * Arguments: bdp - Pointer to the e100_private structure for the board * * * Returns: true - If a link is found * false - If there is no link * */ unsigned char e100_update_link_state(struct e100_private *bdp) { unsigned char link; /* Logical AND PHY link & netif_running */ link = e100_get_link_state(bdp) && netif_running(bdp->device); if (link) { if (!netif_carrier_ok(bdp->device)) netif_carrier_on(bdp->device); } else { if (netif_carrier_ok(bdp->device)) netif_carrier_off(bdp->device); } return link; }
static int e100_cable_diag(struct e100_private *bdp) { int saved_open_circut = 0xffff; int saved_short_circut = 0xffff; int saved_distance = 0xffff; int saved_same = 0; int cable_status = E100_CABLE_UNKNOWN; int i; /* If we have link, */ if (e100_get_link_state(bdp)) return E100_CABLE_OK; if (bdp->rev_id < D102_REV_ID) return E100_CABLE_UNKNOWN; /* Disable MDI/MDI-X auto switching */ e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, MDI_MDIX_RESET_ALL_MASK); /* Set to 100 Full as required by cable test */ e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, BMCR_SPEED100 | BMCR_FULLDPLX); /* Test up to 100 times */ for (i = 0; i < 100; i++) { u16 ctrl_reg; int distance, open_circut, short_circut, near_end; /* Enable and execute cable test */ e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, (HWI_TEST_ENABLE | HWI_TEST_EXECUTE)); /* Wait for cable test finished */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/100 + 1); /* Read results */ e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg); distance = ctrl_reg & HWI_TEST_DISTANCE; open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM; short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM; if ((distance == saved_distance) && (open_circut == saved_open_circut) && (short_circut == saved_short_circut)) saved_same++; else { saved_same = 0; saved_distance = distance; saved_open_circut = open_circut; saved_short_circut = short_circut; } /* If results are the same 3 times */ if (saved_same == 3) { near_end = ((distance * HWI_REGISTER_GRANULARITY) < HWI_NEAR_END_BOUNDARY); if (open_circut) cable_status = (near_end) ? E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR; if (short_circut) cable_status = (near_end) ? E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR; break; } } /* Reset cable test */ e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK); return cable_status; }