📄 ixgb_hw.c
字号:
/****************************************************************************** * Writes a word to a device over the Management Data Interface (MDI) bus. * This interface is used to manage Physical layer devices. * * hw - Struct containing variables accessed by hw code * reg_address - Offset of device register being read. * phy_address - Address of device on MDI. * device_type - Also known as the Device ID or DID. * data - 16-bit value to be written * * Returns: void. * * The 82597EX has support for several MDI access methods. This routine * uses the new protocol MDI Single Command and Address Operation. * This requires that first an address cycle command is sent, followed by a * write command. *****************************************************************************/static voidixgb_write_phy_reg(struct ixgb_hw *hw, uint32_t reg_address, uint32_t phy_address, uint32_t device_type, uint16_t data){ uint32_t i; uint32_t command = 0; ASSERT(reg_address <= IXGB_MAX_PHY_REG_ADDRESS); ASSERT(phy_address <= IXGB_MAX_PHY_ADDRESS); ASSERT(device_type <= IXGB_MAX_PHY_DEV_TYPE); /* Put the data in the MDIO Read/Write Data register */ IXGB_WRITE_REG(hw, MSRWD, (uint32_t)data); /* Setup and write the address cycle command */ command = ((reg_address << IXGB_MSCA_NP_ADDR_SHIFT) | (device_type << IXGB_MSCA_DEV_TYPE_SHIFT) | (phy_address << IXGB_MSCA_PHY_ADDR_SHIFT) | (IXGB_MSCA_ADDR_CYCLE | IXGB_MSCA_MDI_COMMAND)); IXGB_WRITE_REG(hw, MSCA, command); /************************************************************** ** Check every 10 usec to see if the address cycle completed ** The COMMAND bit will clear when the operation is complete. ** This may take as long as 64 usecs (we'll wait 100 usecs max) ** from the CPU Write to the Ready bit assertion. **************************************************************/ for(i = 0; i < 10; i++) { udelay(10); command = IXGB_READ_REG(hw, MSCA); if ((command & IXGB_MSCA_MDI_COMMAND) == 0) break; } ASSERT((command & IXGB_MSCA_MDI_COMMAND) == 0); /* Address cycle complete, setup and write the write command */ command = ((reg_address << IXGB_MSCA_NP_ADDR_SHIFT) | (device_type << IXGB_MSCA_DEV_TYPE_SHIFT) | (phy_address << IXGB_MSCA_PHY_ADDR_SHIFT) | (IXGB_MSCA_WRITE | IXGB_MSCA_MDI_COMMAND)); IXGB_WRITE_REG(hw, MSCA, command); /************************************************************** ** Check every 10 usec to see if the read command completed ** The COMMAND bit will clear when the operation is complete. ** The write may take as long as 64 usecs (we'll wait 100 usecs max) ** from the CPU Write to the Ready bit assertion. **************************************************************/ for(i = 0; i < 10; i++) { udelay(10); command = IXGB_READ_REG(hw, MSCA); if ((command & IXGB_MSCA_MDI_COMMAND) == 0) break; } ASSERT((command & IXGB_MSCA_MDI_COMMAND) == 0); /* Operation is complete, return. */}/****************************************************************************** * Checks to see if the link status of the hardware has changed. * * hw - Struct containing variables accessed by hw code * * Called by any function that needs to check the link status of the adapter. *****************************************************************************/voidixgb_check_for_link(struct ixgb_hw *hw){ uint32_t status_reg; uint32_t xpcss_reg; DEBUGFUNC("ixgb_check_for_link"); xpcss_reg = IXGB_READ_REG(hw, XPCSS); status_reg = IXGB_READ_REG(hw, STATUS); if ((xpcss_reg & IXGB_XPCSS_ALIGN_STATUS) && (status_reg & IXGB_STATUS_LU)) { hw->link_up = TRUE; } else if (!(xpcss_reg & IXGB_XPCSS_ALIGN_STATUS) && (status_reg & IXGB_STATUS_LU)) { DEBUGOUT("XPCSS Not Aligned while Status:LU is set.\n"); hw->link_up = ixgb_link_reset(hw); } else { /* * 82597EX errata. Since the lane deskew problem may prevent * link, reset the link before reporting link down. */ hw->link_up = ixgb_link_reset(hw); } /* Anything else for 10 Gig?? */}/****************************************************************************** * Check for a bad link condition that may have occured. * The indication is that the RFC / LFC registers may be incrementing * continually. A full adapter reset is required to recover. * * hw - Struct containing variables accessed by hw code * * Called by any function that needs to check the link status of the adapter. *****************************************************************************/boolean_t ixgb_check_for_bad_link(struct ixgb_hw *hw){ uint32_t newLFC, newRFC; boolean_t bad_link_returncode = FALSE; if (hw->phy_type == ixgb_phy_type_txn17401) { newLFC = IXGB_READ_REG(hw, LFC); newRFC = IXGB_READ_REG(hw, RFC); if ((hw->lastLFC + 250 < newLFC) || (hw->lastRFC + 250 < newRFC)) { DEBUGOUT ("BAD LINK! too many LFC/RFC since last check\n"); bad_link_returncode = TRUE; } hw->lastLFC = newLFC; hw->lastRFC = newRFC; } return bad_link_returncode;}/****************************************************************************** * Clears all hardware statistics counters. * * hw - Struct containing variables accessed by shared code *****************************************************************************/static voidixgb_clear_hw_cntrs(struct ixgb_hw *hw){ volatile uint32_t temp_reg; DEBUGFUNC("ixgb_clear_hw_cntrs"); /* if we are stopped or resetting exit gracefully */ if(hw->adapter_stopped) { DEBUGOUT("Exiting because the adapter is stopped!!!\n"); return; } temp_reg = IXGB_READ_REG(hw, TPRL); temp_reg = IXGB_READ_REG(hw, TPRH); temp_reg = IXGB_READ_REG(hw, GPRCL); temp_reg = IXGB_READ_REG(hw, GPRCH); temp_reg = IXGB_READ_REG(hw, BPRCL); temp_reg = IXGB_READ_REG(hw, BPRCH); temp_reg = IXGB_READ_REG(hw, MPRCL); temp_reg = IXGB_READ_REG(hw, MPRCH); temp_reg = IXGB_READ_REG(hw, UPRCL); temp_reg = IXGB_READ_REG(hw, UPRCH); temp_reg = IXGB_READ_REG(hw, VPRCL); temp_reg = IXGB_READ_REG(hw, VPRCH); temp_reg = IXGB_READ_REG(hw, JPRCL); temp_reg = IXGB_READ_REG(hw, JPRCH); temp_reg = IXGB_READ_REG(hw, GORCL); temp_reg = IXGB_READ_REG(hw, GORCH); temp_reg = IXGB_READ_REG(hw, TORL); temp_reg = IXGB_READ_REG(hw, TORH); temp_reg = IXGB_READ_REG(hw, RNBC); temp_reg = IXGB_READ_REG(hw, RUC); temp_reg = IXGB_READ_REG(hw, ROC); temp_reg = IXGB_READ_REG(hw, RLEC); temp_reg = IXGB_READ_REG(hw, CRCERRS); temp_reg = IXGB_READ_REG(hw, ICBC); temp_reg = IXGB_READ_REG(hw, ECBC); temp_reg = IXGB_READ_REG(hw, MPC); temp_reg = IXGB_READ_REG(hw, TPTL); temp_reg = IXGB_READ_REG(hw, TPTH); temp_reg = IXGB_READ_REG(hw, GPTCL); temp_reg = IXGB_READ_REG(hw, GPTCH); temp_reg = IXGB_READ_REG(hw, BPTCL); temp_reg = IXGB_READ_REG(hw, BPTCH); temp_reg = IXGB_READ_REG(hw, MPTCL); temp_reg = IXGB_READ_REG(hw, MPTCH); temp_reg = IXGB_READ_REG(hw, UPTCL); temp_reg = IXGB_READ_REG(hw, UPTCH); temp_reg = IXGB_READ_REG(hw, VPTCL); temp_reg = IXGB_READ_REG(hw, VPTCH); temp_reg = IXGB_READ_REG(hw, JPTCL); temp_reg = IXGB_READ_REG(hw, JPTCH); temp_reg = IXGB_READ_REG(hw, GOTCL); temp_reg = IXGB_READ_REG(hw, GOTCH); temp_reg = IXGB_READ_REG(hw, TOTL); temp_reg = IXGB_READ_REG(hw, TOTH); temp_reg = IXGB_READ_REG(hw, DC); temp_reg = IXGB_READ_REG(hw, PLT64C); temp_reg = IXGB_READ_REG(hw, TSCTC); temp_reg = IXGB_READ_REG(hw, TSCTFC); temp_reg = IXGB_READ_REG(hw, IBIC); temp_reg = IXGB_READ_REG(hw, RFC); temp_reg = IXGB_READ_REG(hw, LFC); temp_reg = IXGB_READ_REG(hw, PFRC); temp_reg = IXGB_READ_REG(hw, PFTC); temp_reg = IXGB_READ_REG(hw, MCFRC); temp_reg = IXGB_READ_REG(hw, MCFTC); temp_reg = IXGB_READ_REG(hw, XONRXC); temp_reg = IXGB_READ_REG(hw, XONTXC); temp_reg = IXGB_READ_REG(hw, XOFFRXC); temp_reg = IXGB_READ_REG(hw, XOFFTXC); temp_reg = IXGB_READ_REG(hw, RJC); return;}/****************************************************************************** * Turns on the software controllable LED * * hw - Struct containing variables accessed by shared code *****************************************************************************/voidixgb_led_on(struct ixgb_hw *hw){ uint32_t ctrl0_reg = IXGB_READ_REG(hw, CTRL0); /* To turn on the LED, clear software-definable pin 0 (SDP0). */ ctrl0_reg &= ~IXGB_CTRL0_SDP0; IXGB_WRITE_REG(hw, CTRL0, ctrl0_reg); return;}/****************************************************************************** * Turns off the software controllable LED * * hw - Struct containing variables accessed by shared code *****************************************************************************/voidixgb_led_off(struct ixgb_hw *hw){ uint32_t ctrl0_reg = IXGB_READ_REG(hw, CTRL0); /* To turn off the LED, set software-definable pin 0 (SDP0). */ ctrl0_reg |= IXGB_CTRL0_SDP0; IXGB_WRITE_REG(hw, CTRL0, ctrl0_reg); return;}/****************************************************************************** * Gets the current PCI bus type, speed, and width of the hardware * * hw - Struct containing variables accessed by shared code *****************************************************************************/static voidixgb_get_bus_info(struct ixgb_hw *hw){ uint32_t status_reg; status_reg = IXGB_READ_REG(hw, STATUS); hw->bus.type = (status_reg & IXGB_STATUS_PCIX_MODE) ? ixgb_bus_type_pcix : ixgb_bus_type_pci; if (hw->bus.type == ixgb_bus_type_pci) { hw->bus.speed = (status_reg & IXGB_STATUS_PCI_SPD) ? ixgb_bus_speed_66 : ixgb_bus_speed_33; } else { switch (status_reg & IXGB_STATUS_PCIX_SPD_MASK) { case IXGB_STATUS_PCIX_SPD_66: hw->bus.speed = ixgb_bus_speed_66; break; case IXGB_STATUS_PCIX_SPD_100: hw->bus.speed = ixgb_bus_speed_100; break; case IXGB_STATUS_PCIX_SPD_133: hw->bus.speed = ixgb_bus_speed_133; break; default: hw->bus.speed = ixgb_bus_speed_reserved; break; } } hw->bus.width = (status_reg & IXGB_STATUS_BUS64) ? ixgb_bus_width_64 : ixgb_bus_width_32; return;}/****************************************************************************** * Tests a MAC address to ensure it is a valid Individual Address * * mac_addr - pointer to MAC address. * *****************************************************************************/static boolean_tmac_addr_valid(uint8_t *mac_addr){ boolean_t is_valid = TRUE; DEBUGFUNC("mac_addr_valid"); /* Make sure it is not a multicast address */ if (IS_MULTICAST(mac_addr)) { DEBUGOUT("MAC address is multicast\n"); is_valid = FALSE; } /* Not a broadcast address */ else if (IS_BROADCAST(mac_addr)) { DEBUGOUT("MAC address is broadcast\n"); is_valid = FALSE; } /* Reject the zero address */ else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 && mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) { DEBUGOUT("MAC address is all zeros\n"); is_valid = FALSE; } return (is_valid);}/****************************************************************************** * Resets the 10GbE link. Waits the settle time and returns the state of * the link. * * hw - Struct containing variables accessed by shared code *****************************************************************************/boolean_tixgb_link_reset(struct ixgb_hw *hw){ boolean_t link_status = FALSE; uint8_t wait_retries = MAX_RESET_ITERATIONS; uint8_t lrst_retries = MAX_RESET_ITERATIONS; do { /* Reset the link */ IXGB_WRITE_REG(hw, CTRL0, IXGB_READ_REG(hw, CTRL0) | IXGB_CTRL0_LRST); /* Wait for link-up and lane re-alignment */ do { udelay(IXGB_DELAY_USECS_AFTER_LINK_RESET); link_status = ((IXGB_READ_REG(hw, STATUS) & IXGB_STATUS_LU) && (IXGB_READ_REG(hw, XPCSS) & IXGB_XPCSS_ALIGN_STATUS)) ? TRUE : FALSE; } while (!link_status && --wait_retries); } while (!link_status && --lrst_retries); return link_status;}/****************************************************************************** * Resets the 10GbE optics module. * * hw - Struct containing variables accessed by shared code *****************************************************************************/voidixgb_optics_reset(struct ixgb_hw *hw){ if (hw->phy_type == ixgb_phy_type_txn17401) { uint16_t mdio_reg; ixgb_write_phy_reg(hw, MDIO_PMA_PMD_CR1, IXGB_PHY_ADDRESS, MDIO_PMA_PMD_DID, MDIO_PMA_PMD_CR1_RESET); mdio_reg = ixgb_read_phy_reg( hw, MDIO_PMA_PMD_CR1, IXGB_PHY_ADDRESS, MDIO_PMA_PMD_DID); } return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -