+
+/*****************************************************************************
+ * This function reads the cookie from ARC ram.
+ *
+ * returns: - E1000_SUCCESS .
+ ****************************************************************************/
+int32_t
+e1000_host_if_read_cookie(struct e1000_hw * hw, uint8_t *buffer)
+{
+ uint8_t i;
+ uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET;
+ uint8_t length = E1000_MNG_DHCP_COOKIE_LENGTH;
+
+ length = (length >> 2);
+ offset = (offset >> 2);
+
+ for (i = 0; i < length; i++) {
+ *((uint32_t *) buffer + i) =
+ E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset + i);
+ }
+ return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks whether the HOST IF is enabled for command operaton
+ * and also checks whether the previous command is completed.
+ * It busy waits in case of previous command is not completed.
+ *
+ * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or
+ * timeout
+ * - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+e1000_mng_enable_host_if(struct e1000_hw * hw)
+{
+ uint32_t hicr;
+ uint8_t i;
+
+ /* Check that the host interface is enabled. */
+ hicr = E1000_READ_REG(hw, HICR);
+ if ((hicr & E1000_HICR_EN) == 0) {
+ DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+ /* check the previous command is completed */
+ for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+ hicr = E1000_READ_REG(hw, HICR);
+ if (!(hicr & E1000_HICR_C))
+ break;
+ msec_delay_irq(1);
+ }
+
+ if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+ DEBUGOUT("Previous command timeout failed .\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+ return E1000_SUCCESS;
+}
+
+/*****************************************************************************
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient way.
+ * Also fills up the sum of the buffer in *buffer parameter.
+ *
+ * returns - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+e1000_mng_host_if_write(struct e1000_hw * hw, uint8_t *buffer,
+ uint16_t length, uint16_t offset, uint8_t *sum)
+{
+ uint8_t *tmp;
+ uint8_t *bufptr = buffer;
+ uint32_t data;
+ uint16_t remaining, i, j, prev_bytes;
+
+ /* sum = only sum of the data and it is not checksum */
+
+ if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+ return -E1000_ERR_PARAM;
+ }
+
+ tmp = (uint8_t *)&data;
+ prev_bytes = offset & 0x3;
+ offset &= 0xFFFC;
+ offset >>= 2;
+
+ if (prev_bytes) {
+ data = E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset);
+ for (j = prev_bytes; j < sizeof(uint32_t); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset, data);
+ length -= j - prev_bytes;
+ offset++;
+ }
+
+ remaining = length & 0x3;
+ length -= remaining;
+
+ /* Calculate length in DWORDs */
+ length >>= 2;
+
+ /* The device driver writes the relevant command block into the
+ * ram area. */
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < sizeof(uint32_t); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+
+ E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+ }
+ if (remaining) {
+ for (j = 0; j < sizeof(uint32_t); j++) {
+ if (j < remaining)
+ *(tmp + j) = *bufptr++;
+ else
+ *(tmp + j) = 0;
+
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data);
+ }
+
+ return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function writes the command header after does the checksum calculation.
+ *
+ * returns - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+e1000_mng_write_cmd_header(struct e1000_hw * hw,
+ struct e1000_host_mng_command_header * hdr)
+{
+ uint16_t i;
+ uint8_t sum;
+ uint8_t *buffer;
+
+ /* Write the whole command header structure which includes sum of
+ * the buffer */
+
+ uint16_t length = sizeof(struct e1000_host_mng_command_header);
+
+ sum = hdr->checksum;
+ hdr->checksum = 0;
+
+ buffer = (uint8_t *) hdr;
+ i = length;
+ while(i--)
+ sum += buffer[i];
+
+ hdr->checksum = 0 - sum;
+
+ length >>= 2;
+ /* The device driver writes the relevant command block into the ram area. */
+ for (i = 0; i < length; i++)
+ E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i));
+
+ return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function indicates to ARC that a new command is pending which completes
+ * one write operation by the driver.
+ *
+ * returns - E1000_SUCCESS for success.
+ ****************************************************************************/
+int32_t
+e1000_mng_write_commit(
+ struct e1000_hw * hw)
+{
+ uint32_t hicr;
+
+ hicr = E1000_READ_REG(hw, HICR);
+ /* Setting this bit tells the ARC that a new command is pending. */
+ E1000_WRITE_REG(hw, HICR, hicr | E1000_HICR_C);
+
+ return E1000_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * This function checks the mode of the firmware.
+ *
+ * returns - TRUE when the mode is IAMT or FALSE.
+ ****************************************************************************/
+boolean_t
+e1000_check_mng_mode(
+ struct e1000_hw *hw)
+{
+ uint32_t fwsm;
+
+ fwsm = E1000_READ_REG(hw, FWSM);
+
+ if((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/*****************************************************************************
+ * This function writes the dhcp info .
+ ****************************************************************************/
+int32_t
+e1000_mng_write_dhcp_info(struct e1000_hw * hw, uint8_t *buffer,
+ uint16_t length)
+{
+ int32_t ret_val;
+ struct e1000_host_mng_command_header hdr;
+
+ hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+ hdr.command_length = length;
+ hdr.reserved1 = 0;
+ hdr.reserved2 = 0;
+ hdr.checksum = 0;
+
+ ret_val = e1000_mng_enable_host_if(hw);
+ if (ret_val == E1000_SUCCESS) {
+ ret_val = e1000_mng_host_if_write(hw, buffer, length, sizeof(hdr),
+ &(hdr.checksum));
+ if (ret_val == E1000_SUCCESS) {
+ ret_val = e1000_mng_write_cmd_header(hw, &hdr);
+ if (ret_val == E1000_SUCCESS)
+ ret_val = e1000_mng_write_commit(hw);
+ }
+ }
+ return ret_val;
+}
+
+
+/*****************************************************************************
+ * This function calculates the checksum.
+ *
+ * returns - checksum of buffer contents.
+ ****************************************************************************/
+uint8_t
+e1000_calculate_mng_checksum(char *buffer, uint32_t length)
+{
+ uint8_t sum = 0;
+ uint32_t i;
+
+ if (!buffer)
+ return 0;
+
+ for (i=0; i < length; i++)
+ sum += buffer[i];
+
+ return (uint8_t) (0 - sum);
+}
+
+/*****************************************************************************
+ * This function checks whether tx pkt filtering needs to be enabled or not.
+ *
+ * returns - TRUE for packet filtering or FALSE.
+ ****************************************************************************/
+boolean_t
+e1000_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+ /* called in init as well as watchdog timer functions */
+
+ int32_t ret_val, checksum;
+ boolean_t tx_filter = FALSE;
+ struct e1000_host_mng_dhcp_cookie *hdr = &(hw->mng_cookie);
+ uint8_t *buffer = (uint8_t *) &(hw->mng_cookie);
+
+ if (e1000_check_mng_mode(hw)) {
+ ret_val = e1000_mng_enable_host_if(hw);
+ if (ret_val == E1000_SUCCESS) {
+ ret_val = e1000_host_if_read_cookie(hw, buffer);
+ if (ret_val == E1000_SUCCESS) {
+ checksum = hdr->checksum;
+ hdr->checksum = 0;
+ if ((hdr->signature == E1000_IAMT_SIGNATURE) &&
+ checksum == e1000_calculate_mng_checksum((char *)buffer,
+ E1000_MNG_DHCP_COOKIE_LENGTH)) {
+ if (hdr->status &
+ E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT)
+ tx_filter = TRUE;
+ } else
+ tx_filter = TRUE;
+ } else
+ tx_filter = TRUE;
+ }
+ }
+
+ hw->tx_pkt_filtering = tx_filter;
+ return tx_filter;
+}
+
+/******************************************************************************
+ * Verifies the hardware needs to allow ARPs to be processed by the host
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - TRUE/FALSE
+ *
+ *****************************************************************************/
+uint32_t
+e1000_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+ uint32_t manc;
+ uint32_t fwsm, factps;
+
+ if (hw->asf_firmware_present) {
+ manc = E1000_READ_REG(hw, MANC);
+
+ if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+ !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+ return FALSE;
+ if (e1000_arc_subsystem_valid(hw) == TRUE) {
+ fwsm = E1000_READ_REG(hw, FWSM);
+ factps = E1000_READ_REG(hw, FACTPS);
+
+ if (((fwsm & E1000_FWSM_MODE_MASK) ==
+ (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)) &&
+ (factps & E1000_FACTPS_MNGCG))
+ return TRUE;
+ } else
+ if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int32_t
+e1000_polarity_reversal_workaround(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t mii_status_reg;
+ uint16_t i;
+
+ /* Polarity reversal workaround for forced 10F/10H links. */
+
+ /* Disable the transmitter on the PHY */
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+ if(ret_val)
+ return ret_val;
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+ if(ret_val)
+ return ret_val;
+
+ /* This loop will early-out if the NO link condition has been met. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Link Status bit
+ * to be clear.
+ */
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ if((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break;
+ msec_delay_irq(100);
+ }
+
+ /* Recommended delay time after link has been lost */
+ msec_delay_irq(1000);
+
+ /* Now we will re-enable th transmitter on the PHY */
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+ if(ret_val)
+ return ret_val;
+ msec_delay_irq(50);
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
+ if(ret_val)
+ return ret_val;
+ msec_delay_irq(50);
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
+ if(ret_val)
+ return ret_val;
+ msec_delay_irq(50);
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+ if(ret_val)
+ return ret_val;
+
+ /* This loop will early-out if the link condition has been met. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Link Status bit
+ * to be set.
+ */
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+ if(ret_val)
+ return ret_val;
+
+ if(mii_status_reg & MII_SR_LINK_STATUS) break;
+ msec_delay_irq(100);
+ }
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Disables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+e1000_set_pci_express_master_disable(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+
+ DEBUGFUNC("e1000_set_pci_express_master_disable");
+
+ if (hw->bus_type != e1000_bus_type_pci_express)
+ return;
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/***************************************************************************
+ *
+ * Enables PCI-Express master access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - none.
+ *
+ ***************************************************************************/
+void
+e1000_enable_pciex_master(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+
+ DEBUGFUNC("e1000_enable_pciex_master");
+
+ if (hw->bus_type != e1000_bus_type_pci_express)
+ return;
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Disables PCI-Express master access and verifies there are no pending requests
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_MASTER_REQUESTS_PENDING if master disable bit hasn't
+ * caused the master requests to be disabled.
+ * E1000_SUCCESS master requests disabled.
+ *
+ ******************************************************************************/
+int32_t
+e1000_disable_pciex_master(struct e1000_hw *hw)
+{
+ int32_t timeout = MASTER_DISABLE_TIMEOUT; /* 80ms */
+
+ DEBUGFUNC("e1000_disable_pciex_master");
+
+ if (hw->bus_type != e1000_bus_type_pci_express)
+ return E1000_SUCCESS;
+
+ e1000_set_pci_express_master_disable(hw);
+
+ while(timeout) {
+ if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
+ break;
+ else
+ udelay(100);
+ timeout--;
+ }
+
+ if(!timeout) {
+ DEBUGOUT("Master requests are pending.\n");
+ return -E1000_ERR_MASTER_REQUESTS_PENDING;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Check for EEPROM Auto Read bit done.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ * E1000_SUCCESS at any other case.
+ *
+ ******************************************************************************/
+int32_t
+e1000_get_auto_rd_done(struct e1000_hw *hw)
+{
+ int32_t timeout = AUTO_READ_DONE_TIMEOUT;
+
+ DEBUGFUNC("e1000_get_auto_rd_done");
+
+ switch (hw->mac_type) {
+ default:
+ msec_delay(5);
+ break;
+ case e1000_82573:
+ while(timeout) {
+ if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
+ else msec_delay(1);
+ timeout--;
+ }
+
+ if(!timeout) {
+ DEBUGOUT("Auto read by HW from EEPROM has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+ break;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * Checks if the PHY configuration is done
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+e1000_get_phy_cfg_done(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_get_phy_cfg_done");
+
+ /* Simply wait for 10ms */
+ msec_delay(10);
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Using the combination of SMBI and SWESMBI semaphore bits when resetting
+ * adapter or Eeprom access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_EEPROM if fail to access EEPROM.
+ * E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+int32_t
+e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+ int32_t timeout;
+ uint32_t swsm;
+
+ DEBUGFUNC("e1000_get_hw_eeprom_semaphore");
+
+ if(!hw->eeprom_semaphore_present)
+ return E1000_SUCCESS;
+
+
+ /* Get the FW semaphore. */
+ timeout = hw->eeprom.word_size + 1;
+ while(timeout) {
+ swsm = E1000_READ_REG(hw, SWSM);
+ swsm |= E1000_SWSM_SWESMBI;
+ E1000_WRITE_REG(hw, SWSM, swsm);
+ /* if we managed to set the bit we got the semaphore. */
+ swsm = E1000_READ_REG(hw, SWSM);
+ if(swsm & E1000_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ timeout--;
+ }
+
+ if(!timeout) {
+ /* Release semaphores */
+ e1000_put_hw_eeprom_semaphore(hw);
+ DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ * This function clears HW semaphore bits.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - None.
+ *
+ ***************************************************************************/
+void
+e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
+{
+ uint32_t swsm;
+
+ DEBUGFUNC("e1000_put_hw_eeprom_semaphore");
+
+ if(!hw->eeprom_semaphore_present)
+ return;
+
+ swsm = E1000_READ_REG(hw, SWSM);
+ /* Release both semaphores. */
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+ E1000_WRITE_REG(hw, SWSM, swsm);
+}
+
+/******************************************************************************
+ * Checks if PHY reset is blocked due to SOL/IDER session, for example.
+ * Returning E1000_BLK_PHY_RESET isn't necessarily an error. But it's up to
+ * the caller to figure out how to deal with it.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_BLK_PHY_RESET
+ * E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+e1000_check_phy_reset_block(struct e1000_hw *hw)
+{
+ uint32_t manc = 0;
+ if(hw->mac_type > e1000_82547_rev_2)
+ manc = E1000_READ_REG(hw, MANC);
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+ E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+uint8_t
+e1000_arc_subsystem_valid(struct e1000_hw *hw)
+{
+ uint32_t fwsm;
+
+ /* On 8257x silicon, registers in the range of 0x8800 - 0x8FFC
+ * may not be provided a DMA clock when no manageability features are
+ * enabled. We do not want to perform any reads/writes to these registers
+ * if this is the case. We read FWSM to determine the manageability mode.
+ */
+ switch (hw->mac_type) {
+ case e1000_82573:
+ fwsm = E1000_READ_REG(hw, FWSM);
+ if((fwsm & E1000_FWSM_MODE_MASK) != 0)
+ return TRUE;
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+
+