175eba5b6SRobert Mustacchi /******************************************************************************
275eba5b6SRobert Mustacchi 
3*49b78600SRobert Mustacchi   Copyright (c) 2001-2015, Intel Corporation
475eba5b6SRobert Mustacchi   All rights reserved.
575eba5b6SRobert Mustacchi 
675eba5b6SRobert Mustacchi   Redistribution and use in source and binary forms, with or without
775eba5b6SRobert Mustacchi   modification, are permitted provided that the following conditions are met:
875eba5b6SRobert Mustacchi 
975eba5b6SRobert Mustacchi    1. Redistributions of source code must retain the above copyright notice,
1075eba5b6SRobert Mustacchi       this list of conditions and the following disclaimer.
1175eba5b6SRobert Mustacchi 
1275eba5b6SRobert Mustacchi    2. Redistributions in binary form must reproduce the above copyright
1375eba5b6SRobert Mustacchi       notice, this list of conditions and the following disclaimer in the
1475eba5b6SRobert Mustacchi       documentation and/or other materials provided with the distribution.
1575eba5b6SRobert Mustacchi 
1675eba5b6SRobert Mustacchi    3. Neither the name of the Intel Corporation nor the names of its
1775eba5b6SRobert Mustacchi       contributors may be used to endorse or promote products derived from
1875eba5b6SRobert Mustacchi       this software without specific prior written permission.
1975eba5b6SRobert Mustacchi 
2075eba5b6SRobert Mustacchi   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2175eba5b6SRobert Mustacchi   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2275eba5b6SRobert Mustacchi   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2375eba5b6SRobert Mustacchi   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2475eba5b6SRobert Mustacchi   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2575eba5b6SRobert Mustacchi   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2675eba5b6SRobert Mustacchi   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2775eba5b6SRobert Mustacchi   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2875eba5b6SRobert Mustacchi   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2975eba5b6SRobert Mustacchi   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3075eba5b6SRobert Mustacchi   POSSIBILITY OF SUCH DAMAGE.
3175eba5b6SRobert Mustacchi 
3275eba5b6SRobert Mustacchi ******************************************************************************/
3375eba5b6SRobert Mustacchi /*$FreeBSD$*/
3475eba5b6SRobert Mustacchi 
3575eba5b6SRobert Mustacchi #include "e1000_api.h"
3675eba5b6SRobert Mustacchi /**
3775eba5b6SRobert Mustacchi  *  e1000_calculate_checksum - Calculate checksum for buffer
3875eba5b6SRobert Mustacchi  *  @buffer: pointer to EEPROM
3975eba5b6SRobert Mustacchi  *  @length: size of EEPROM to calculate a checksum for
4075eba5b6SRobert Mustacchi  *
4175eba5b6SRobert Mustacchi  *  Calculates the checksum for some buffer on a specified length.  The
4275eba5b6SRobert Mustacchi  *  checksum calculated is returned.
4375eba5b6SRobert Mustacchi  **/
e1000_calculate_checksum(u8 * buffer,u32 length)4475eba5b6SRobert Mustacchi u8 e1000_calculate_checksum(u8 *buffer, u32 length)
4575eba5b6SRobert Mustacchi {
4675eba5b6SRobert Mustacchi 	u32 i;
4775eba5b6SRobert Mustacchi 	u8 sum = 0;
4875eba5b6SRobert Mustacchi 
4975eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_calculate_checksum");
5075eba5b6SRobert Mustacchi 
5175eba5b6SRobert Mustacchi 	if (!buffer)
5275eba5b6SRobert Mustacchi 		return 0;
5375eba5b6SRobert Mustacchi 
5475eba5b6SRobert Mustacchi 	for (i = 0; i < length; i++)
5575eba5b6SRobert Mustacchi 		sum += buffer[i];
5675eba5b6SRobert Mustacchi 
5775eba5b6SRobert Mustacchi 	return (u8) (0 - sum);
5875eba5b6SRobert Mustacchi }
5975eba5b6SRobert Mustacchi 
6075eba5b6SRobert Mustacchi /**
6175eba5b6SRobert Mustacchi  *  e1000_mng_enable_host_if_generic - Checks host interface is enabled
6275eba5b6SRobert Mustacchi  *  @hw: pointer to the HW structure
6375eba5b6SRobert Mustacchi  *
6475eba5b6SRobert Mustacchi  *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
6575eba5b6SRobert Mustacchi  *
6675eba5b6SRobert Mustacchi  *  This function checks whether the HOST IF is enabled for command operation
6775eba5b6SRobert Mustacchi  *  and also checks whether the previous command is completed.  It busy waits
6875eba5b6SRobert Mustacchi  *  in case of previous command is not completed.
6975eba5b6SRobert Mustacchi  **/
e1000_mng_enable_host_if_generic(struct e1000_hw * hw)7075eba5b6SRobert Mustacchi s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
7175eba5b6SRobert Mustacchi {
7275eba5b6SRobert Mustacchi 	u32 hicr;
7375eba5b6SRobert Mustacchi 	u8 i;
7475eba5b6SRobert Mustacchi 
7575eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_mng_enable_host_if_generic");
7675eba5b6SRobert Mustacchi 
7775eba5b6SRobert Mustacchi 	if (!hw->mac.arc_subsystem_valid) {
7875eba5b6SRobert Mustacchi 		DEBUGOUT("ARC subsystem not valid.\n");
7975eba5b6SRobert Mustacchi 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
8075eba5b6SRobert Mustacchi 	}
8175eba5b6SRobert Mustacchi 
8275eba5b6SRobert Mustacchi 	/* Check that the host interface is enabled. */
8375eba5b6SRobert Mustacchi 	hicr = E1000_READ_REG(hw, E1000_HICR);
8475eba5b6SRobert Mustacchi 	if (!(hicr & E1000_HICR_EN)) {
8575eba5b6SRobert Mustacchi 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
8675eba5b6SRobert Mustacchi 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
8775eba5b6SRobert Mustacchi 	}
8875eba5b6SRobert Mustacchi 	/* check the previous command is completed */
8975eba5b6SRobert Mustacchi 	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
9075eba5b6SRobert Mustacchi 		hicr = E1000_READ_REG(hw, E1000_HICR);
9175eba5b6SRobert Mustacchi 		if (!(hicr & E1000_HICR_C))
9275eba5b6SRobert Mustacchi 			break;
9375eba5b6SRobert Mustacchi 		msec_delay_irq(1);
9475eba5b6SRobert Mustacchi 	}
9575eba5b6SRobert Mustacchi 
9675eba5b6SRobert Mustacchi 	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
9775eba5b6SRobert Mustacchi 		DEBUGOUT("Previous command timeout failed .\n");
9875eba5b6SRobert Mustacchi 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
9975eba5b6SRobert Mustacchi 	}
10075eba5b6SRobert Mustacchi 
10175eba5b6SRobert Mustacchi 	return E1000_SUCCESS;
10275eba5b6SRobert Mustacchi }
10375eba5b6SRobert Mustacchi 
10475eba5b6SRobert Mustacchi /**
10575eba5b6SRobert Mustacchi  *  e1000_check_mng_mode_generic - Generic check management mode
10675eba5b6SRobert Mustacchi  *  @hw: pointer to the HW structure
10775eba5b6SRobert Mustacchi  *
10875eba5b6SRobert Mustacchi  *  Reads the firmware semaphore register and returns TRUE (>0) if
10975eba5b6SRobert Mustacchi  *  manageability is enabled, else FALSE (0).
11075eba5b6SRobert Mustacchi  **/
e1000_check_mng_mode_generic(struct e1000_hw * hw)11175eba5b6SRobert Mustacchi bool e1000_check_mng_mode_generic(struct e1000_hw *hw)
11275eba5b6SRobert Mustacchi {
11375eba5b6SRobert Mustacchi 	u32 fwsm = E1000_READ_REG(hw, E1000_FWSM);
11475eba5b6SRobert Mustacchi 
11575eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_check_mng_mode_generic");
11675eba5b6SRobert Mustacchi 
11775eba5b6SRobert Mustacchi 
11875eba5b6SRobert Mustacchi 	return (fwsm & E1000_FWSM_MODE_MASK) ==
11975eba5b6SRobert Mustacchi 		(E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
12075eba5b6SRobert Mustacchi }
12175eba5b6SRobert Mustacchi 
12275eba5b6SRobert Mustacchi /**
12375eba5b6SRobert Mustacchi  *  e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on Tx
12475eba5b6SRobert Mustacchi  *  @hw: pointer to the HW structure
12575eba5b6SRobert Mustacchi  *
12675eba5b6SRobert Mustacchi  *  Enables packet filtering on transmit packets if manageability is enabled
12775eba5b6SRobert Mustacchi  *  and host interface is enabled.
12875eba5b6SRobert Mustacchi  **/
e1000_enable_tx_pkt_filtering_generic(struct e1000_hw * hw)12975eba5b6SRobert Mustacchi bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
13075eba5b6SRobert Mustacchi {
13175eba5b6SRobert Mustacchi 	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
13275eba5b6SRobert Mustacchi 	u32 *buffer = (u32 *)&hw->mng_cookie;
13375eba5b6SRobert Mustacchi 	u32 offset;
13475eba5b6SRobert Mustacchi 	s32 ret_val, hdr_csum, csum;
13575eba5b6SRobert Mustacchi 	u8 i, len;
13675eba5b6SRobert Mustacchi 
13775eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
13875eba5b6SRobert Mustacchi 
13975eba5b6SRobert Mustacchi 	hw->mac.tx_pkt_filtering = TRUE;
14075eba5b6SRobert Mustacchi 
14175eba5b6SRobert Mustacchi 	/* No manageability, no filtering */
14275eba5b6SRobert Mustacchi 	if (!hw->mac.ops.check_mng_mode(hw)) {
14375eba5b6SRobert Mustacchi 		hw->mac.tx_pkt_filtering = FALSE;
14475eba5b6SRobert Mustacchi 		return hw->mac.tx_pkt_filtering;
14575eba5b6SRobert Mustacchi 	}
14675eba5b6SRobert Mustacchi 
14775eba5b6SRobert Mustacchi 	/* If we can't read from the host interface for whatever
14875eba5b6SRobert Mustacchi 	 * reason, disable filtering.
14975eba5b6SRobert Mustacchi 	 */
15075eba5b6SRobert Mustacchi 	ret_val = e1000_mng_enable_host_if_generic(hw);
15175eba5b6SRobert Mustacchi 	if (ret_val != E1000_SUCCESS) {
15275eba5b6SRobert Mustacchi 		hw->mac.tx_pkt_filtering = FALSE;
15375eba5b6SRobert Mustacchi 		return hw->mac.tx_pkt_filtering;
15475eba5b6SRobert Mustacchi 	}
15575eba5b6SRobert Mustacchi 
15675eba5b6SRobert Mustacchi 	/* Read in the header.  Length and offset are in dwords. */
15775eba5b6SRobert Mustacchi 	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
15875eba5b6SRobert Mustacchi 	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
15975eba5b6SRobert Mustacchi 	for (i = 0; i < len; i++)
16075eba5b6SRobert Mustacchi 		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
16175eba5b6SRobert Mustacchi 							   offset + i);
16275eba5b6SRobert Mustacchi 	hdr_csum = hdr->checksum;
16375eba5b6SRobert Mustacchi 	hdr->checksum = 0;
16475eba5b6SRobert Mustacchi 	csum = e1000_calculate_checksum((u8 *)hdr,
16575eba5b6SRobert Mustacchi 					E1000_MNG_DHCP_COOKIE_LENGTH);
16675eba5b6SRobert Mustacchi 	/* If either the checksums or signature don't match, then
16775eba5b6SRobert Mustacchi 	 * the cookie area isn't considered valid, in which case we
16875eba5b6SRobert Mustacchi 	 * take the safe route of assuming Tx filtering is enabled.
16975eba5b6SRobert Mustacchi 	 */
17075eba5b6SRobert Mustacchi 	if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
17175eba5b6SRobert Mustacchi 		hw->mac.tx_pkt_filtering = TRUE;
17275eba5b6SRobert Mustacchi 		return hw->mac.tx_pkt_filtering;
17375eba5b6SRobert Mustacchi 	}
17475eba5b6SRobert Mustacchi 
17575eba5b6SRobert Mustacchi 	/* Cookie area is valid, make the final check for filtering. */
17675eba5b6SRobert Mustacchi 	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
17775eba5b6SRobert Mustacchi 		hw->mac.tx_pkt_filtering = FALSE;
17875eba5b6SRobert Mustacchi 
17975eba5b6SRobert Mustacchi 	return hw->mac.tx_pkt_filtering;
18075eba5b6SRobert Mustacchi }
18175eba5b6SRobert Mustacchi 
18275eba5b6SRobert Mustacchi /**
18375eba5b6SRobert Mustacchi  *  e1000_mng_write_cmd_header_generic - Writes manageability command header
18475eba5b6SRobert Mustacchi  *  @hw: pointer to the HW structure
18575eba5b6SRobert Mustacchi  *  @hdr: pointer to the host interface command header
18675eba5b6SRobert Mustacchi  *
18775eba5b6SRobert Mustacchi  *  Writes the command header after does the checksum calculation.
18875eba5b6SRobert Mustacchi  **/
e1000_mng_write_cmd_header_generic(struct e1000_hw * hw,struct e1000_host_mng_command_header * hdr)18975eba5b6SRobert Mustacchi s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
19075eba5b6SRobert Mustacchi 				      struct e1000_host_mng_command_header *hdr)
19175eba5b6SRobert Mustacchi {
19275eba5b6SRobert Mustacchi 	u16 i, length = sizeof(struct e1000_host_mng_command_header);
19375eba5b6SRobert Mustacchi 
19475eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_mng_write_cmd_header_generic");
19575eba5b6SRobert Mustacchi 
19675eba5b6SRobert Mustacchi 	/* Write the whole command header structure with new checksum. */
19775eba5b6SRobert Mustacchi 
19875eba5b6SRobert Mustacchi 	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
19975eba5b6SRobert Mustacchi 
20075eba5b6SRobert Mustacchi 	length >>= 2;
20175eba5b6SRobert Mustacchi 	/* Write the relevant command block into the ram area. */
20275eba5b6SRobert Mustacchi 	for (i = 0; i < length; i++) {
20375eba5b6SRobert Mustacchi 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
20475eba5b6SRobert Mustacchi 					    *((u32 *) hdr + i));
20575eba5b6SRobert Mustacchi 		E1000_WRITE_FLUSH(hw);
20675eba5b6SRobert Mustacchi 	}
20775eba5b6SRobert Mustacchi 
20875eba5b6SRobert Mustacchi 	return E1000_SUCCESS;
20975eba5b6SRobert Mustacchi }
21075eba5b6SRobert Mustacchi 
21175eba5b6SRobert Mustacchi /**
21275eba5b6SRobert Mustacchi  *  e1000_mng_host_if_write_generic - Write to the manageability host interface
21375eba5b6SRobert Mustacchi  *  @hw: pointer to the HW structure
21475eba5b6SRobert Mustacchi  *  @buffer: pointer to the host interface buffer
21575eba5b6SRobert Mustacchi  *  @length: size of the buffer
21675eba5b6SRobert Mustacchi  *  @offset: location in the buffer to write to
21775eba5b6SRobert Mustacchi  *  @sum: sum of the data (not checksum)
21875eba5b6SRobert Mustacchi  *
21975eba5b6SRobert Mustacchi  *  This function writes the buffer content at the offset given on the host if.
22075eba5b6SRobert Mustacchi  *  It also does alignment considerations to do the writes in most efficient
22175eba5b6SRobert Mustacchi  *  way.  Also fills up the sum of the buffer in *buffer parameter.
22275eba5b6SRobert Mustacchi  **/
e1000_mng_host_if_write_generic(struct e1000_hw * hw,u8 * buffer,u16 length,u16 offset,u8 * sum)22375eba5b6SRobert Mustacchi s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
22475eba5b6SRobert Mustacchi 				    u16 length, u16 offset, u8 *sum)
22575eba5b6SRobert Mustacchi {
22675eba5b6SRobert Mustacchi 	u8 *tmp;
22775eba5b6SRobert Mustacchi 	u8 *bufptr = buffer;
22875eba5b6SRobert Mustacchi 	u32 data = 0;
22975eba5b6SRobert Mustacchi 	u16 remaining, i, j, prev_bytes;
23075eba5b6SRobert Mustacchi 
23175eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_mng_host_if_write_generic");
23275eba5b6SRobert Mustacchi 
23375eba5b6SRobert Mustacchi 	/* sum = only sum of the data and it is not checksum */
23475eba5b6SRobert Mustacchi 
23575eba5b6SRobert Mustacchi 	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH)
23675eba5b6SRobert Mustacchi 		return -E1000_ERR_PARAM;
23775eba5b6SRobert Mustacchi 
23875eba5b6SRobert Mustacchi 	tmp = (u8 *)&data;
23975eba5b6SRobert Mustacchi 	prev_bytes = offset & 0x3;
24075eba5b6SRobert Mustacchi 	offset >>= 2;
24175eba5b6SRobert Mustacchi 
24275eba5b6SRobert Mustacchi 	if (prev_bytes) {
24375eba5b6SRobert Mustacchi 		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
24475eba5b6SRobert Mustacchi 		for (j = prev_bytes; j < sizeof(u32); j++) {
24575eba5b6SRobert Mustacchi 			*(tmp + j) = *bufptr++;
24675eba5b6SRobert Mustacchi 			*sum += *(tmp + j);
24775eba5b6SRobert Mustacchi 		}
24875eba5b6SRobert Mustacchi 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
24975eba5b6SRobert Mustacchi 		length -= j - prev_bytes;
25075eba5b6SRobert Mustacchi 		offset++;
25175eba5b6SRobert Mustacchi 	}
25275eba5b6SRobert Mustacchi 
25375eba5b6SRobert Mustacchi 	remaining = length & 0x3;
25475eba5b6SRobert Mustacchi 	length -= remaining;
25575eba5b6SRobert Mustacchi 
25675eba5b6SRobert Mustacchi 	/* Calculate length in DWORDs */
25775eba5b6SRobert Mustacchi 	length >>= 2;
25875eba5b6SRobert Mustacchi 
25975eba5b6SRobert Mustacchi 	/* The device driver writes the relevant command block into the
26075eba5b6SRobert Mustacchi 	 * ram area.
26175eba5b6SRobert Mustacchi 	 */
26275eba5b6SRobert Mustacchi 	for (i = 0; i < length; i++) {
26375eba5b6SRobert Mustacchi 		for (j = 0; j < sizeof(u32); j++) {
26475eba5b6SRobert Mustacchi 			*(tmp + j) = *bufptr++;
26575eba5b6SRobert Mustacchi 			*sum += *(tmp + j);
26675eba5b6SRobert Mustacchi 		}
26775eba5b6SRobert Mustacchi 
26875eba5b6SRobert Mustacchi 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
26975eba5b6SRobert Mustacchi 					    data);
27075eba5b6SRobert Mustacchi 	}
27175eba5b6SRobert Mustacchi 	if (remaining) {
27275eba5b6SRobert Mustacchi 		for (j = 0; j < sizeof(u32); j++) {
27375eba5b6SRobert Mustacchi 			if (j < remaining)
27475eba5b6SRobert Mustacchi 				*(tmp + j) = *bufptr++;
27575eba5b6SRobert Mustacchi 			else
27675eba5b6SRobert Mustacchi 				*(tmp + j) = 0;
27775eba5b6SRobert Mustacchi 
27875eba5b6SRobert Mustacchi 			*sum += *(tmp + j);
27975eba5b6SRobert Mustacchi 		}
28075eba5b6SRobert Mustacchi 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
28175eba5b6SRobert Mustacchi 					    data);
28275eba5b6SRobert Mustacchi 	}
28375eba5b6SRobert Mustacchi 
28475eba5b6SRobert Mustacchi 	return E1000_SUCCESS;
28575eba5b6SRobert Mustacchi }
28675eba5b6SRobert Mustacchi 
28775eba5b6SRobert Mustacchi /**
28875eba5b6SRobert Mustacchi  *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
28975eba5b6SRobert Mustacchi  *  @hw: pointer to the HW structure
29075eba5b6SRobert Mustacchi  *  @buffer: pointer to the host interface
29175eba5b6SRobert Mustacchi  *  @length: size of the buffer
29275eba5b6SRobert Mustacchi  *
29375eba5b6SRobert Mustacchi  *  Writes the DHCP information to the host interface.
29475eba5b6SRobert Mustacchi  **/
e1000_mng_write_dhcp_info_generic(struct e1000_hw * hw,u8 * buffer,u16 length)29575eba5b6SRobert Mustacchi s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
29675eba5b6SRobert Mustacchi 				      u16 length)
29775eba5b6SRobert Mustacchi {
29875eba5b6SRobert Mustacchi 	struct e1000_host_mng_command_header hdr;
29975eba5b6SRobert Mustacchi 	s32 ret_val;
30075eba5b6SRobert Mustacchi 	u32 hicr;
30175eba5b6SRobert Mustacchi 
30275eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
30375eba5b6SRobert Mustacchi 
30475eba5b6SRobert Mustacchi 	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
30575eba5b6SRobert Mustacchi 	hdr.command_length = length;
30675eba5b6SRobert Mustacchi 	hdr.reserved1 = 0;
30775eba5b6SRobert Mustacchi 	hdr.reserved2 = 0;
30875eba5b6SRobert Mustacchi 	hdr.checksum = 0;
30975eba5b6SRobert Mustacchi 
31075eba5b6SRobert Mustacchi 	/* Enable the host interface */
31175eba5b6SRobert Mustacchi 	ret_val = e1000_mng_enable_host_if_generic(hw);
31275eba5b6SRobert Mustacchi 	if (ret_val)
31375eba5b6SRobert Mustacchi 		return ret_val;
31475eba5b6SRobert Mustacchi 
31575eba5b6SRobert Mustacchi 	/* Populate the host interface with the contents of "buffer". */
31675eba5b6SRobert Mustacchi 	ret_val = e1000_mng_host_if_write_generic(hw, buffer, length,
31775eba5b6SRobert Mustacchi 						  sizeof(hdr), &(hdr.checksum));
31875eba5b6SRobert Mustacchi 	if (ret_val)
31975eba5b6SRobert Mustacchi 		return ret_val;
32075eba5b6SRobert Mustacchi 
32175eba5b6SRobert Mustacchi 	/* Write the manageability command header */
32275eba5b6SRobert Mustacchi 	ret_val = e1000_mng_write_cmd_header_generic(hw, &hdr);
32375eba5b6SRobert Mustacchi 	if (ret_val)
32475eba5b6SRobert Mustacchi 		return ret_val;
32575eba5b6SRobert Mustacchi 
32675eba5b6SRobert Mustacchi 	/* Tell the ARC a new command is pending. */
32775eba5b6SRobert Mustacchi 	hicr = E1000_READ_REG(hw, E1000_HICR);
32875eba5b6SRobert Mustacchi 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
32975eba5b6SRobert Mustacchi 
33075eba5b6SRobert Mustacchi 	return E1000_SUCCESS;
33175eba5b6SRobert Mustacchi }
33275eba5b6SRobert Mustacchi 
33375eba5b6SRobert Mustacchi /**
33475eba5b6SRobert Mustacchi  *  e1000_enable_mng_pass_thru - Check if management passthrough is needed
33575eba5b6SRobert Mustacchi  *  @hw: pointer to the HW structure
33675eba5b6SRobert Mustacchi  *
33775eba5b6SRobert Mustacchi  *  Verifies the hardware needs to leave interface enabled so that frames can
33875eba5b6SRobert Mustacchi  *  be directed to and from the management interface.
33975eba5b6SRobert Mustacchi  **/
e1000_enable_mng_pass_thru(struct e1000_hw * hw)34075eba5b6SRobert Mustacchi bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
34175eba5b6SRobert Mustacchi {
34275eba5b6SRobert Mustacchi 	u32 manc;
34375eba5b6SRobert Mustacchi 	u32 fwsm, factps;
34475eba5b6SRobert Mustacchi 
34575eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_enable_mng_pass_thru");
34675eba5b6SRobert Mustacchi 
34775eba5b6SRobert Mustacchi 	if (!hw->mac.asf_firmware_present)
34875eba5b6SRobert Mustacchi 		return FALSE;
34975eba5b6SRobert Mustacchi 
35075eba5b6SRobert Mustacchi 	manc = E1000_READ_REG(hw, E1000_MANC);
35175eba5b6SRobert Mustacchi 
35275eba5b6SRobert Mustacchi 	if (!(manc & E1000_MANC_RCV_TCO_EN))
35375eba5b6SRobert Mustacchi 		return FALSE;
35475eba5b6SRobert Mustacchi 
35575eba5b6SRobert Mustacchi 	if (hw->mac.has_fwsm) {
35675eba5b6SRobert Mustacchi 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
35775eba5b6SRobert Mustacchi 		factps = E1000_READ_REG(hw, E1000_FACTPS);
35875eba5b6SRobert Mustacchi 
35975eba5b6SRobert Mustacchi 		if (!(factps & E1000_FACTPS_MNGCG) &&
36075eba5b6SRobert Mustacchi 		    ((fwsm & E1000_FWSM_MODE_MASK) ==
36175eba5b6SRobert Mustacchi 		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)))
36275eba5b6SRobert Mustacchi 			return TRUE;
36375eba5b6SRobert Mustacchi 	} else if ((hw->mac.type == e1000_82574) ||
36475eba5b6SRobert Mustacchi 		   (hw->mac.type == e1000_82583)) {
36575eba5b6SRobert Mustacchi 		u16 data;
366c124a83eSRobert Mustacchi 		s32 ret_val;
36775eba5b6SRobert Mustacchi 
36875eba5b6SRobert Mustacchi 		factps = E1000_READ_REG(hw, E1000_FACTPS);
369c124a83eSRobert Mustacchi 		ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
370c124a83eSRobert Mustacchi 		if (ret_val)
371c124a83eSRobert Mustacchi 			return FALSE;
37275eba5b6SRobert Mustacchi 
37375eba5b6SRobert Mustacchi 		if (!(factps & E1000_FACTPS_MNGCG) &&
37475eba5b6SRobert Mustacchi 		    ((data & E1000_NVM_INIT_CTRL2_MNGM) ==
37575eba5b6SRobert Mustacchi 		     (e1000_mng_mode_pt << 13)))
37675eba5b6SRobert Mustacchi 			return TRUE;
37775eba5b6SRobert Mustacchi 	} else if ((manc & E1000_MANC_SMBUS_EN) &&
37875eba5b6SRobert Mustacchi 		   !(manc & E1000_MANC_ASF_EN)) {
379c124a83eSRobert Mustacchi 		return TRUE;
38075eba5b6SRobert Mustacchi 	}
38175eba5b6SRobert Mustacchi 
38275eba5b6SRobert Mustacchi 	return FALSE;
38375eba5b6SRobert Mustacchi }
38475eba5b6SRobert Mustacchi 
38575eba5b6SRobert Mustacchi /**
38675eba5b6SRobert Mustacchi  *  e1000_host_interface_command - Writes buffer to host interface
38775eba5b6SRobert Mustacchi  *  @hw: pointer to the HW structure
38875eba5b6SRobert Mustacchi  *  @buffer: contains a command to write
38975eba5b6SRobert Mustacchi  *  @length: the byte length of the buffer, must be multiple of 4 bytes
39075eba5b6SRobert Mustacchi  *
39175eba5b6SRobert Mustacchi  *  Writes a buffer to the Host Interface.  Upon success, returns E1000_SUCCESS
39275eba5b6SRobert Mustacchi  *  else returns E1000_ERR_HOST_INTERFACE_COMMAND.
39375eba5b6SRobert Mustacchi  **/
e1000_host_interface_command(struct e1000_hw * hw,u8 * buffer,u32 length)39475eba5b6SRobert Mustacchi s32 e1000_host_interface_command(struct e1000_hw *hw, u8 *buffer, u32 length)
39575eba5b6SRobert Mustacchi {
39675eba5b6SRobert Mustacchi 	u32 hicr, i;
39775eba5b6SRobert Mustacchi 
39875eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_host_interface_command");
39975eba5b6SRobert Mustacchi 
40075eba5b6SRobert Mustacchi 	if (!(hw->mac.arc_subsystem_valid)) {
40175eba5b6SRobert Mustacchi 		DEBUGOUT("Hardware doesn't support host interface command.\n");
40275eba5b6SRobert Mustacchi 		return E1000_SUCCESS;
40375eba5b6SRobert Mustacchi 	}
40475eba5b6SRobert Mustacchi 
40575eba5b6SRobert Mustacchi 	if (!hw->mac.asf_firmware_present) {
40675eba5b6SRobert Mustacchi 		DEBUGOUT("Firmware is not present.\n");
40775eba5b6SRobert Mustacchi 		return E1000_SUCCESS;
40875eba5b6SRobert Mustacchi 	}
40975eba5b6SRobert Mustacchi 
41075eba5b6SRobert Mustacchi 	if (length == 0 || length & 0x3 ||
41175eba5b6SRobert Mustacchi 	    length > E1000_HI_MAX_BLOCK_BYTE_LENGTH) {
41275eba5b6SRobert Mustacchi 		DEBUGOUT("Buffer length failure.\n");
41375eba5b6SRobert Mustacchi 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
41475eba5b6SRobert Mustacchi 	}
41575eba5b6SRobert Mustacchi 
41675eba5b6SRobert Mustacchi 	/* Check that the host interface is enabled. */
41775eba5b6SRobert Mustacchi 	hicr = E1000_READ_REG(hw, E1000_HICR);
41875eba5b6SRobert Mustacchi 	if (!(hicr & E1000_HICR_EN)) {
41975eba5b6SRobert Mustacchi 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
42075eba5b6SRobert Mustacchi 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
42175eba5b6SRobert Mustacchi 	}
42275eba5b6SRobert Mustacchi 
42375eba5b6SRobert Mustacchi 	/* Calculate length in DWORDs */
42475eba5b6SRobert Mustacchi 	length >>= 2;
42575eba5b6SRobert Mustacchi 
42675eba5b6SRobert Mustacchi 	/* The device driver writes the relevant command block
42775eba5b6SRobert Mustacchi 	 * into the ram area.
42875eba5b6SRobert Mustacchi 	 */
42975eba5b6SRobert Mustacchi 	for (i = 0; i < length; i++)
43075eba5b6SRobert Mustacchi 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
43175eba5b6SRobert Mustacchi 					    *((u32 *)buffer + i));
43275eba5b6SRobert Mustacchi 
43375eba5b6SRobert Mustacchi 	/* Setting this bit tells the ARC that a new command is pending. */
43475eba5b6SRobert Mustacchi 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
43575eba5b6SRobert Mustacchi 
43675eba5b6SRobert Mustacchi 	for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
43775eba5b6SRobert Mustacchi 		hicr = E1000_READ_REG(hw, E1000_HICR);
43875eba5b6SRobert Mustacchi 		if (!(hicr & E1000_HICR_C))
43975eba5b6SRobert Mustacchi 			break;
44075eba5b6SRobert Mustacchi 		msec_delay(1);
44175eba5b6SRobert Mustacchi 	}
44275eba5b6SRobert Mustacchi 
44375eba5b6SRobert Mustacchi 	/* Check command successful completion. */
44475eba5b6SRobert Mustacchi 	if (i == E1000_HI_COMMAND_TIMEOUT ||
44575eba5b6SRobert Mustacchi 	    (!(E1000_READ_REG(hw, E1000_HICR) & E1000_HICR_SV))) {
44675eba5b6SRobert Mustacchi 		DEBUGOUT("Command has failed with no status valid.\n");
44775eba5b6SRobert Mustacchi 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
44875eba5b6SRobert Mustacchi 	}
44975eba5b6SRobert Mustacchi 
45075eba5b6SRobert Mustacchi 	for (i = 0; i < length; i++)
45175eba5b6SRobert Mustacchi 		*((u32 *)buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
45275eba5b6SRobert Mustacchi 								  E1000_HOST_IF,
45375eba5b6SRobert Mustacchi 								  i);
45475eba5b6SRobert Mustacchi 
45575eba5b6SRobert Mustacchi 	return E1000_SUCCESS;
45675eba5b6SRobert Mustacchi }
45775eba5b6SRobert Mustacchi /**
45875eba5b6SRobert Mustacchi  *  e1000_load_firmware - Writes proxy FW code buffer to host interface
45975eba5b6SRobert Mustacchi  *                        and execute.
46075eba5b6SRobert Mustacchi  *  @hw: pointer to the HW structure
46175eba5b6SRobert Mustacchi  *  @buffer: contains a firmware to write
46275eba5b6SRobert Mustacchi  *  @length: the byte length of the buffer, must be multiple of 4 bytes
46375eba5b6SRobert Mustacchi  *
46475eba5b6SRobert Mustacchi  *  Upon success returns E1000_SUCCESS, returns E1000_ERR_CONFIG if not enabled
46575eba5b6SRobert Mustacchi  *  in HW else returns E1000_ERR_HOST_INTERFACE_COMMAND.
46675eba5b6SRobert Mustacchi  **/
e1000_load_firmware(struct e1000_hw * hw,u8 * buffer,u32 length)46775eba5b6SRobert Mustacchi s32 e1000_load_firmware(struct e1000_hw *hw, u8 *buffer, u32 length)
46875eba5b6SRobert Mustacchi {
46975eba5b6SRobert Mustacchi 	u32 hicr, hibba, fwsm, icr, i;
47075eba5b6SRobert Mustacchi 
47175eba5b6SRobert Mustacchi 	DEBUGFUNC("e1000_load_firmware");
47275eba5b6SRobert Mustacchi 
47375eba5b6SRobert Mustacchi 	if (hw->mac.type < e1000_i210) {
47475eba5b6SRobert Mustacchi 		DEBUGOUT("Hardware doesn't support loading FW by the driver\n");
47575eba5b6SRobert Mustacchi 		return -E1000_ERR_CONFIG;
47675eba5b6SRobert Mustacchi 	}
47775eba5b6SRobert Mustacchi 
47875eba5b6SRobert Mustacchi 	/* Check that the host interface is enabled. */
47975eba5b6SRobert Mustacchi 	hicr = E1000_READ_REG(hw, E1000_HICR);
48075eba5b6SRobert Mustacchi 	if (!(hicr & E1000_HICR_EN)) {
48175eba5b6SRobert Mustacchi 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
48275eba5b6SRobert Mustacchi 		return -E1000_ERR_CONFIG;
48375eba5b6SRobert Mustacchi 	}
48475eba5b6SRobert Mustacchi 	if (!(hicr & E1000_HICR_MEMORY_BASE_EN)) {
48575eba5b6SRobert Mustacchi 		DEBUGOUT("E1000_HICR_MEMORY_BASE_EN bit disabled.\n");
48675eba5b6SRobert Mustacchi 		return -E1000_ERR_CONFIG;
48775eba5b6SRobert Mustacchi 	}
48875eba5b6SRobert Mustacchi 
48975eba5b6SRobert Mustacchi 	if (length == 0 || length & 0x3 || length > E1000_HI_FW_MAX_LENGTH) {
49075eba5b6SRobert Mustacchi 		DEBUGOUT("Buffer length failure.\n");
49175eba5b6SRobert Mustacchi 		return -E1000_ERR_INVALID_ARGUMENT;
49275eba5b6SRobert Mustacchi 	}
49375eba5b6SRobert Mustacchi 
49475eba5b6SRobert Mustacchi 	/* Clear notification from ROM-FW by reading ICR register */
49575eba5b6SRobert Mustacchi 	icr = E1000_READ_REG(hw, E1000_ICR_V2);
49675eba5b6SRobert Mustacchi 
49775eba5b6SRobert Mustacchi 	/* Reset ROM-FW */
49875eba5b6SRobert Mustacchi 	hicr = E1000_READ_REG(hw, E1000_HICR);
49975eba5b6SRobert Mustacchi 	hicr |= E1000_HICR_FW_RESET_ENABLE;
50075eba5b6SRobert Mustacchi 	E1000_WRITE_REG(hw, E1000_HICR, hicr);
50175eba5b6SRobert Mustacchi 	hicr |= E1000_HICR_FW_RESET;
50275eba5b6SRobert Mustacchi 	E1000_WRITE_REG(hw, E1000_HICR, hicr);
50375eba5b6SRobert Mustacchi 	E1000_WRITE_FLUSH(hw);
50475eba5b6SRobert Mustacchi 
50575eba5b6SRobert Mustacchi 	/* Wait till MAC notifies about its readiness after ROM-FW reset */
50675eba5b6SRobert Mustacchi 	for (i = 0; i < (E1000_HI_COMMAND_TIMEOUT * 2); i++) {
50775eba5b6SRobert Mustacchi 		icr = E1000_READ_REG(hw, E1000_ICR_V2);
50875eba5b6SRobert Mustacchi 		if (icr & E1000_ICR_MNG)
50975eba5b6SRobert Mustacchi 			break;
51075eba5b6SRobert Mustacchi 		msec_delay(1);
51175eba5b6SRobert Mustacchi 	}
51275eba5b6SRobert Mustacchi 
51375eba5b6SRobert Mustacchi 	/* Check for timeout */
51475eba5b6SRobert Mustacchi 	if (i == E1000_HI_COMMAND_TIMEOUT) {
51575eba5b6SRobert Mustacchi 		DEBUGOUT("FW reset failed.\n");
51675eba5b6SRobert Mustacchi 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
51775eba5b6SRobert Mustacchi 	}
51875eba5b6SRobert Mustacchi 
51975eba5b6SRobert Mustacchi 	/* Wait till MAC is ready to accept new FW code */
52075eba5b6SRobert Mustacchi 	for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
52175eba5b6SRobert Mustacchi 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
52275eba5b6SRobert Mustacchi 		if ((fwsm & E1000_FWSM_FW_VALID) &&
52375eba5b6SRobert Mustacchi 		    ((fwsm & E1000_FWSM_MODE_MASK) >> E1000_FWSM_MODE_SHIFT ==
52475eba5b6SRobert Mustacchi 		    E1000_FWSM_HI_EN_ONLY_MODE))
52575eba5b6SRobert Mustacchi 			break;
52675eba5b6SRobert Mustacchi 		msec_delay(1);
52775eba5b6SRobert Mustacchi 	}
52875eba5b6SRobert Mustacchi 
52975eba5b6SRobert Mustacchi 	/* Check for timeout */
53075eba5b6SRobert Mustacchi 	if (i == E1000_HI_COMMAND_TIMEOUT) {
53175eba5b6SRobert Mustacchi 		DEBUGOUT("FW reset failed.\n");
53275eba5b6SRobert Mustacchi 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
53375eba5b6SRobert Mustacchi 	}
53475eba5b6SRobert Mustacchi 
53575eba5b6SRobert Mustacchi 	/* Calculate length in DWORDs */
53675eba5b6SRobert Mustacchi 	length >>= 2;
53775eba5b6SRobert Mustacchi 
53875eba5b6SRobert Mustacchi 	/* The device driver writes the relevant FW code block
53975eba5b6SRobert Mustacchi 	 * into the ram area in DWORDs via 1kB ram addressing window.
54075eba5b6SRobert Mustacchi 	 */
54175eba5b6SRobert Mustacchi 	for (i = 0; i < length; i++) {
54275eba5b6SRobert Mustacchi 		if (!(i % E1000_HI_FW_BLOCK_DWORD_LENGTH)) {
54375eba5b6SRobert Mustacchi 			/* Point to correct 1kB ram window */
54475eba5b6SRobert Mustacchi 			hibba = E1000_HI_FW_BASE_ADDRESS +
54575eba5b6SRobert Mustacchi 				((E1000_HI_FW_BLOCK_DWORD_LENGTH << 2) *
54675eba5b6SRobert Mustacchi 				(i / E1000_HI_FW_BLOCK_DWORD_LENGTH));
54775eba5b6SRobert Mustacchi 
54875eba5b6SRobert Mustacchi 			E1000_WRITE_REG(hw, E1000_HIBBA, hibba);
54975eba5b6SRobert Mustacchi 		}
55075eba5b6SRobert Mustacchi 
55175eba5b6SRobert Mustacchi 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
55275eba5b6SRobert Mustacchi 					    i % E1000_HI_FW_BLOCK_DWORD_LENGTH,
55375eba5b6SRobert Mustacchi 					    *((u32 *)buffer + i));
55475eba5b6SRobert Mustacchi 	}
55575eba5b6SRobert Mustacchi 
55675eba5b6SRobert Mustacchi 	/* Setting this bit tells the ARC that a new FW is ready to execute. */
55775eba5b6SRobert Mustacchi 	hicr = E1000_READ_REG(hw, E1000_HICR);
55875eba5b6SRobert Mustacchi 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
55975eba5b6SRobert Mustacchi 
56075eba5b6SRobert Mustacchi 	for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
56175eba5b6SRobert Mustacchi 		hicr = E1000_READ_REG(hw, E1000_HICR);
56275eba5b6SRobert Mustacchi 		if (!(hicr & E1000_HICR_C))
56375eba5b6SRobert Mustacchi 			break;
56475eba5b6SRobert Mustacchi 		msec_delay(1);
56575eba5b6SRobert Mustacchi 	}
56675eba5b6SRobert Mustacchi 
56775eba5b6SRobert Mustacchi 	/* Check for successful FW start. */
56875eba5b6SRobert Mustacchi 	if (i == E1000_HI_COMMAND_TIMEOUT) {
56975eba5b6SRobert Mustacchi 		DEBUGOUT("New FW did not start within timeout period.\n");
57075eba5b6SRobert Mustacchi 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
57175eba5b6SRobert Mustacchi 	}
57275eba5b6SRobert Mustacchi 
57375eba5b6SRobert Mustacchi 	return E1000_SUCCESS;
57475eba5b6SRobert Mustacchi }
57575eba5b6SRobert Mustacchi 
57675eba5b6SRobert Mustacchi 
577