xref: /dflybsd-src/sys/dev/netif/ig_hal/e1000_manage.c (revision 01a55482b42bba8de64caeb8c9ede647a9208734)
19c80d176SSepherosa Ziehau /******************************************************************************
29c80d176SSepherosa Ziehau 
3*01a55482SSepherosa Ziehau   Copyright (c) 2001-2019, Intel Corporation
49c80d176SSepherosa Ziehau   All rights reserved.
59c80d176SSepherosa Ziehau 
69c80d176SSepherosa Ziehau   Redistribution and use in source and binary forms, with or without
79c80d176SSepherosa Ziehau   modification, are permitted provided that the following conditions are met:
89c80d176SSepherosa Ziehau 
99c80d176SSepherosa Ziehau    1. Redistributions of source code must retain the above copyright notice,
109c80d176SSepherosa Ziehau       this list of conditions and the following disclaimer.
119c80d176SSepherosa Ziehau 
129c80d176SSepherosa Ziehau    2. Redistributions in binary form must reproduce the above copyright
139c80d176SSepherosa Ziehau       notice, this list of conditions and the following disclaimer in the
149c80d176SSepherosa Ziehau       documentation and/or other materials provided with the distribution.
159c80d176SSepherosa Ziehau 
169c80d176SSepherosa Ziehau    3. Neither the name of the Intel Corporation nor the names of its
179c80d176SSepherosa Ziehau       contributors may be used to endorse or promote products derived from
189c80d176SSepherosa Ziehau       this software without specific prior written permission.
199c80d176SSepherosa Ziehau 
209c80d176SSepherosa Ziehau   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
219c80d176SSepherosa Ziehau   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229c80d176SSepherosa Ziehau   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239c80d176SSepherosa Ziehau   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
249c80d176SSepherosa Ziehau   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
259c80d176SSepherosa Ziehau   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
269c80d176SSepherosa Ziehau   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
279c80d176SSepherosa Ziehau   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
289c80d176SSepherosa Ziehau   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
299c80d176SSepherosa Ziehau   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
309c80d176SSepherosa Ziehau   POSSIBILITY OF SUCH DAMAGE.
319c80d176SSepherosa Ziehau 
329c80d176SSepherosa Ziehau ******************************************************************************/
3374dc3754SSepherosa Ziehau /*$FreeBSD$*/
349c80d176SSepherosa Ziehau 
359c80d176SSepherosa Ziehau #include "e1000_api.h"
36*01a55482SSepherosa Ziehau #include "e1000_manage.h"
37*01a55482SSepherosa Ziehau 
389c80d176SSepherosa Ziehau /**
399c80d176SSepherosa Ziehau  *  e1000_calculate_checksum - Calculate checksum for buffer
409c80d176SSepherosa Ziehau  *  @buffer: pointer to EEPROM
419c80d176SSepherosa Ziehau  *  @length: size of EEPROM to calculate a checksum for
429c80d176SSepherosa Ziehau  *
439c80d176SSepherosa Ziehau  *  Calculates the checksum for some buffer on a specified length.  The
449c80d176SSepherosa Ziehau  *  checksum calculated is returned.
459c80d176SSepherosa Ziehau  **/
e1000_calculate_checksum(u8 * buffer,u32 length)4665aebe9fSSepherosa Ziehau u8 e1000_calculate_checksum(u8 *buffer, u32 length)
479c80d176SSepherosa Ziehau {
489c80d176SSepherosa Ziehau 	u32 i;
499c80d176SSepherosa Ziehau 	u8 sum = 0;
509c80d176SSepherosa Ziehau 
519c80d176SSepherosa Ziehau 	DEBUGFUNC("e1000_calculate_checksum");
529c80d176SSepherosa Ziehau 
539c80d176SSepherosa Ziehau 	if (!buffer)
549c80d176SSepherosa Ziehau 		return 0;
559c80d176SSepherosa Ziehau 
569c80d176SSepherosa Ziehau 	for (i = 0; i < length; i++)
579c80d176SSepherosa Ziehau 		sum += buffer[i];
589c80d176SSepherosa Ziehau 
599c80d176SSepherosa Ziehau 	return (u8) (0 - sum);
609c80d176SSepherosa Ziehau }
619c80d176SSepherosa Ziehau 
629c80d176SSepherosa Ziehau /**
639c80d176SSepherosa Ziehau  *  e1000_mng_enable_host_if_generic - Checks host interface is enabled
649c80d176SSepherosa Ziehau  *  @hw: pointer to the HW structure
659c80d176SSepherosa Ziehau  *
669c80d176SSepherosa Ziehau  *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
679c80d176SSepherosa Ziehau  *
689c80d176SSepherosa Ziehau  *  This function checks whether the HOST IF is enabled for command operation
699c80d176SSepherosa Ziehau  *  and also checks whether the previous command is completed.  It busy waits
709c80d176SSepherosa Ziehau  *  in case of previous command is not completed.
719c80d176SSepherosa Ziehau  **/
e1000_mng_enable_host_if_generic(struct e1000_hw * hw)729c80d176SSepherosa Ziehau s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
739c80d176SSepherosa Ziehau {
749c80d176SSepherosa Ziehau 	u32 hicr;
759c80d176SSepherosa Ziehau 	u8 i;
769c80d176SSepherosa Ziehau 
779c80d176SSepherosa Ziehau 	DEBUGFUNC("e1000_mng_enable_host_if_generic");
789c80d176SSepherosa Ziehau 
794be59a01SSepherosa Ziehau 	if (!hw->mac.arc_subsystem_valid) {
806a5a645eSSepherosa Ziehau 		DEBUGOUT("ARC subsystem not valid.\n");
814be59a01SSepherosa Ziehau 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
826a5a645eSSepherosa Ziehau 	}
836a5a645eSSepherosa Ziehau 
849c80d176SSepherosa Ziehau 	/* Check that the host interface is enabled. */
859c80d176SSepherosa Ziehau 	hicr = E1000_READ_REG(hw, E1000_HICR);
864be59a01SSepherosa Ziehau 	if (!(hicr & E1000_HICR_EN)) {
879c80d176SSepherosa Ziehau 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
884be59a01SSepherosa Ziehau 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
899c80d176SSepherosa Ziehau 	}
909c80d176SSepherosa Ziehau 	/* check the previous command is completed */
919c80d176SSepherosa Ziehau 	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
929c80d176SSepherosa Ziehau 		hicr = E1000_READ_REG(hw, E1000_HICR);
939c80d176SSepherosa Ziehau 		if (!(hicr & E1000_HICR_C))
949c80d176SSepherosa Ziehau 			break;
959c80d176SSepherosa Ziehau 		msec_delay_irq(1);
969c80d176SSepherosa Ziehau 	}
979c80d176SSepherosa Ziehau 
989c80d176SSepherosa Ziehau 	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
999c80d176SSepherosa Ziehau 		DEBUGOUT("Previous command timeout failed .\n");
1004be59a01SSepherosa Ziehau 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
1019c80d176SSepherosa Ziehau 	}
1029c80d176SSepherosa Ziehau 
1034be59a01SSepherosa Ziehau 	return E1000_SUCCESS;
1049c80d176SSepherosa Ziehau }
1059c80d176SSepherosa Ziehau 
1069c80d176SSepherosa Ziehau /**
1079c80d176SSepherosa Ziehau  *  e1000_check_mng_mode_generic - Generic check management mode
1089c80d176SSepherosa Ziehau  *  @hw: pointer to the HW structure
1099c80d176SSepherosa Ziehau  *
1109c80d176SSepherosa Ziehau  *  Reads the firmware semaphore register and returns TRUE (>0) if
1119c80d176SSepherosa Ziehau  *  manageability is enabled, else FALSE (0).
1129c80d176SSepherosa Ziehau  **/
e1000_check_mng_mode_generic(struct e1000_hw * hw)1139c80d176SSepherosa Ziehau bool e1000_check_mng_mode_generic(struct e1000_hw *hw)
1149c80d176SSepherosa Ziehau {
1156a5a645eSSepherosa Ziehau 	u32 fwsm = E1000_READ_REG(hw, E1000_FWSM);
1169c80d176SSepherosa Ziehau 
1179c80d176SSepherosa Ziehau 	DEBUGFUNC("e1000_check_mng_mode_generic");
1189c80d176SSepherosa Ziehau 
1199c80d176SSepherosa Ziehau 
1209c80d176SSepherosa Ziehau 	return (fwsm & E1000_FWSM_MODE_MASK) ==
1219c80d176SSepherosa Ziehau 		(E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
1229c80d176SSepherosa Ziehau }
1239c80d176SSepherosa Ziehau 
1249c80d176SSepherosa Ziehau /**
1256a5a645eSSepherosa Ziehau  *  e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on Tx
1269c80d176SSepherosa Ziehau  *  @hw: pointer to the HW structure
1279c80d176SSepherosa Ziehau  *
1289c80d176SSepherosa Ziehau  *  Enables packet filtering on transmit packets if manageability is enabled
1299c80d176SSepherosa Ziehau  *  and host interface is enabled.
1309c80d176SSepherosa Ziehau  **/
e1000_enable_tx_pkt_filtering_generic(struct e1000_hw * hw)1319c80d176SSepherosa Ziehau bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
1329c80d176SSepherosa Ziehau {
1339c80d176SSepherosa Ziehau 	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
1349c80d176SSepherosa Ziehau 	u32 *buffer = (u32 *)&hw->mng_cookie;
1359c80d176SSepherosa Ziehau 	u32 offset;
1369c80d176SSepherosa Ziehau 	s32 ret_val, hdr_csum, csum;
1379c80d176SSepherosa Ziehau 	u8 i, len;
1389c80d176SSepherosa Ziehau 
1399c80d176SSepherosa Ziehau 	DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
1409c80d176SSepherosa Ziehau 
1416a5a645eSSepherosa Ziehau 	hw->mac.tx_pkt_filtering = TRUE;
1426a5a645eSSepherosa Ziehau 
1439c80d176SSepherosa Ziehau 	/* No manageability, no filtering */
1449c80d176SSepherosa Ziehau 	if (!hw->mac.ops.check_mng_mode(hw)) {
1456a5a645eSSepherosa Ziehau 		hw->mac.tx_pkt_filtering = FALSE;
1464be59a01SSepherosa Ziehau 		return hw->mac.tx_pkt_filtering;
1479c80d176SSepherosa Ziehau 	}
1489c80d176SSepherosa Ziehau 
149379ebbe7SSepherosa Ziehau 	/* If we can't read from the host interface for whatever
1509c80d176SSepherosa Ziehau 	 * reason, disable filtering.
1519c80d176SSepherosa Ziehau 	 */
152379ebbe7SSepherosa Ziehau 	ret_val = e1000_mng_enable_host_if_generic(hw);
1539c80d176SSepherosa Ziehau 	if (ret_val != E1000_SUCCESS) {
1546a5a645eSSepherosa Ziehau 		hw->mac.tx_pkt_filtering = FALSE;
1554be59a01SSepherosa Ziehau 		return hw->mac.tx_pkt_filtering;
1569c80d176SSepherosa Ziehau 	}
1579c80d176SSepherosa Ziehau 
1589c80d176SSepherosa Ziehau 	/* Read in the header.  Length and offset are in dwords. */
1599c80d176SSepherosa Ziehau 	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
1609c80d176SSepherosa Ziehau 	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
1616a5a645eSSepherosa Ziehau 	for (i = 0; i < len; i++)
1626a5a645eSSepherosa Ziehau 		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
1639c80d176SSepherosa Ziehau 							   offset + i);
1649c80d176SSepherosa Ziehau 	hdr_csum = hdr->checksum;
1659c80d176SSepherosa Ziehau 	hdr->checksum = 0;
1669c80d176SSepherosa Ziehau 	csum = e1000_calculate_checksum((u8 *)hdr,
1679c80d176SSepherosa Ziehau 					E1000_MNG_DHCP_COOKIE_LENGTH);
168379ebbe7SSepherosa Ziehau 	/* If either the checksums or signature don't match, then
1699c80d176SSepherosa Ziehau 	 * the cookie area isn't considered valid, in which case we
1709c80d176SSepherosa Ziehau 	 * take the safe route of assuming Tx filtering is enabled.
1719c80d176SSepherosa Ziehau 	 */
1726a5a645eSSepherosa Ziehau 	if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
1736a5a645eSSepherosa Ziehau 		hw->mac.tx_pkt_filtering = TRUE;
1746a5a645eSSepherosa Ziehau 		return hw->mac.tx_pkt_filtering;
1759c80d176SSepherosa Ziehau 	}
1769c80d176SSepherosa Ziehau 
1774be59a01SSepherosa Ziehau 	/* Cookie area is valid, make the final check for filtering. */
1784be59a01SSepherosa Ziehau 	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
1794be59a01SSepherosa Ziehau 		hw->mac.tx_pkt_filtering = FALSE;
1809c80d176SSepherosa Ziehau 
1814be59a01SSepherosa Ziehau 	return hw->mac.tx_pkt_filtering;
1829c80d176SSepherosa Ziehau }
1839c80d176SSepherosa Ziehau 
1849c80d176SSepherosa Ziehau /**
1859c80d176SSepherosa Ziehau  *  e1000_mng_write_cmd_header_generic - Writes manageability command header
1869c80d176SSepherosa Ziehau  *  @hw: pointer to the HW structure
1879c80d176SSepherosa Ziehau  *  @hdr: pointer to the host interface command header
1889c80d176SSepherosa Ziehau  *
1899c80d176SSepherosa Ziehau  *  Writes the command header after does the checksum calculation.
1909c80d176SSepherosa Ziehau  **/
e1000_mng_write_cmd_header_generic(struct e1000_hw * hw,struct e1000_host_mng_command_header * hdr)1919c80d176SSepherosa Ziehau s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
1929c80d176SSepherosa Ziehau 				      struct e1000_host_mng_command_header *hdr)
1939c80d176SSepherosa Ziehau {
1949c80d176SSepherosa Ziehau 	u16 i, length = sizeof(struct e1000_host_mng_command_header);
1959c80d176SSepherosa Ziehau 
1969c80d176SSepherosa Ziehau 	DEBUGFUNC("e1000_mng_write_cmd_header_generic");
1979c80d176SSepherosa Ziehau 
1989c80d176SSepherosa Ziehau 	/* Write the whole command header structure with new checksum. */
1999c80d176SSepherosa Ziehau 
2009c80d176SSepherosa Ziehau 	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
2019c80d176SSepherosa Ziehau 
2029c80d176SSepherosa Ziehau 	length >>= 2;
2039c80d176SSepherosa Ziehau 	/* Write the relevant command block into the ram area. */
2049c80d176SSepherosa Ziehau 	for (i = 0; i < length; i++) {
2059c80d176SSepherosa Ziehau 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
2069c80d176SSepherosa Ziehau 					    *((u32 *) hdr + i));
2079c80d176SSepherosa Ziehau 		E1000_WRITE_FLUSH(hw);
2089c80d176SSepherosa Ziehau 	}
2099c80d176SSepherosa Ziehau 
2109c80d176SSepherosa Ziehau 	return E1000_SUCCESS;
2119c80d176SSepherosa Ziehau }
2129c80d176SSepherosa Ziehau 
2139c80d176SSepherosa Ziehau /**
2149c80d176SSepherosa Ziehau  *  e1000_mng_host_if_write_generic - Write to the manageability host interface
2159c80d176SSepherosa Ziehau  *  @hw: pointer to the HW structure
2169c80d176SSepherosa Ziehau  *  @buffer: pointer to the host interface buffer
2179c80d176SSepherosa Ziehau  *  @length: size of the buffer
2189c80d176SSepherosa Ziehau  *  @offset: location in the buffer to write to
2199c80d176SSepherosa Ziehau  *  @sum: sum of the data (not checksum)
2209c80d176SSepherosa Ziehau  *
2219c80d176SSepherosa Ziehau  *  This function writes the buffer content at the offset given on the host if.
2229c80d176SSepherosa Ziehau  *  It also does alignment considerations to do the writes in most efficient
2239c80d176SSepherosa Ziehau  *  way.  Also fills up the sum of the buffer in *buffer parameter.
2249c80d176SSepherosa Ziehau  **/
e1000_mng_host_if_write_generic(struct e1000_hw * hw,u8 * buffer,u16 length,u16 offset,u8 * sum)2259c80d176SSepherosa Ziehau s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
2269c80d176SSepherosa Ziehau 				    u16 length, u16 offset, u8 *sum)
2279c80d176SSepherosa Ziehau {
2289c80d176SSepherosa Ziehau 	u8 *tmp;
2299c80d176SSepherosa Ziehau 	u8 *bufptr = buffer;
2309c80d176SSepherosa Ziehau 	u32 data = 0;
2319c80d176SSepherosa Ziehau 	u16 remaining, i, j, prev_bytes;
2329c80d176SSepherosa Ziehau 
2339c80d176SSepherosa Ziehau 	DEBUGFUNC("e1000_mng_host_if_write_generic");
2349c80d176SSepherosa Ziehau 
2359c80d176SSepherosa Ziehau 	/* sum = only sum of the data and it is not checksum */
2369c80d176SSepherosa Ziehau 
2374be59a01SSepherosa Ziehau 	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH)
2384be59a01SSepherosa Ziehau 		return -E1000_ERR_PARAM;
2399c80d176SSepherosa Ziehau 
2409c80d176SSepherosa Ziehau 	tmp = (u8 *)&data;
2419c80d176SSepherosa Ziehau 	prev_bytes = offset & 0x3;
2429c80d176SSepherosa Ziehau 	offset >>= 2;
2439c80d176SSepherosa Ziehau 
2449c80d176SSepherosa Ziehau 	if (prev_bytes) {
2459c80d176SSepherosa Ziehau 		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
2469c80d176SSepherosa Ziehau 		for (j = prev_bytes; j < sizeof(u32); j++) {
2479c80d176SSepherosa Ziehau 			*(tmp + j) = *bufptr++;
2489c80d176SSepherosa Ziehau 			*sum += *(tmp + j);
2499c80d176SSepherosa Ziehau 		}
2509c80d176SSepherosa Ziehau 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
2519c80d176SSepherosa Ziehau 		length -= j - prev_bytes;
2529c80d176SSepherosa Ziehau 		offset++;
2539c80d176SSepherosa Ziehau 	}
2549c80d176SSepherosa Ziehau 
2559c80d176SSepherosa Ziehau 	remaining = length & 0x3;
2569c80d176SSepherosa Ziehau 	length -= remaining;
2579c80d176SSepherosa Ziehau 
2589c80d176SSepherosa Ziehau 	/* Calculate length in DWORDs */
2599c80d176SSepherosa Ziehau 	length >>= 2;
2609c80d176SSepherosa Ziehau 
261379ebbe7SSepherosa Ziehau 	/* The device driver writes the relevant command block into the
2629c80d176SSepherosa Ziehau 	 * ram area.
2639c80d176SSepherosa Ziehau 	 */
2649c80d176SSepherosa Ziehau 	for (i = 0; i < length; i++) {
2659c80d176SSepherosa Ziehau 		for (j = 0; j < sizeof(u32); j++) {
2669c80d176SSepherosa Ziehau 			*(tmp + j) = *bufptr++;
2679c80d176SSepherosa Ziehau 			*sum += *(tmp + j);
2689c80d176SSepherosa Ziehau 		}
2699c80d176SSepherosa Ziehau 
2709c80d176SSepherosa Ziehau 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
2719c80d176SSepherosa Ziehau 					    data);
2729c80d176SSepherosa Ziehau 	}
2739c80d176SSepherosa Ziehau 	if (remaining) {
2749c80d176SSepherosa Ziehau 		for (j = 0; j < sizeof(u32); j++) {
2759c80d176SSepherosa Ziehau 			if (j < remaining)
2769c80d176SSepherosa Ziehau 				*(tmp + j) = *bufptr++;
2779c80d176SSepherosa Ziehau 			else
2789c80d176SSepherosa Ziehau 				*(tmp + j) = 0;
2799c80d176SSepherosa Ziehau 
2809c80d176SSepherosa Ziehau 			*sum += *(tmp + j);
2819c80d176SSepherosa Ziehau 		}
2824be59a01SSepherosa Ziehau 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
2834be59a01SSepherosa Ziehau 					    data);
2849c80d176SSepherosa Ziehau 	}
2859c80d176SSepherosa Ziehau 
2864be59a01SSepherosa Ziehau 	return E1000_SUCCESS;
2874be59a01SSepherosa Ziehau }
2884be59a01SSepherosa Ziehau 
2894be59a01SSepherosa Ziehau /**
2904be59a01SSepherosa Ziehau  *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
2914be59a01SSepherosa Ziehau  *  @hw: pointer to the HW structure
2924be59a01SSepherosa Ziehau  *  @buffer: pointer to the host interface
2934be59a01SSepherosa Ziehau  *  @length: size of the buffer
2944be59a01SSepherosa Ziehau  *
2954be59a01SSepherosa Ziehau  *  Writes the DHCP information to the host interface.
2964be59a01SSepherosa Ziehau  **/
e1000_mng_write_dhcp_info_generic(struct e1000_hw * hw,u8 * buffer,u16 length)2974be59a01SSepherosa Ziehau s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
2984be59a01SSepherosa Ziehau 				      u16 length)
2994be59a01SSepherosa Ziehau {
3004be59a01SSepherosa Ziehau 	struct e1000_host_mng_command_header hdr;
3014be59a01SSepherosa Ziehau 	s32 ret_val;
3024be59a01SSepherosa Ziehau 	u32 hicr;
3034be59a01SSepherosa Ziehau 
3044be59a01SSepherosa Ziehau 	DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
3054be59a01SSepherosa Ziehau 
3064be59a01SSepherosa Ziehau 	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
3074be59a01SSepherosa Ziehau 	hdr.command_length = length;
3084be59a01SSepherosa Ziehau 	hdr.reserved1 = 0;
3094be59a01SSepherosa Ziehau 	hdr.reserved2 = 0;
3104be59a01SSepherosa Ziehau 	hdr.checksum = 0;
3114be59a01SSepherosa Ziehau 
3124be59a01SSepherosa Ziehau 	/* Enable the host interface */
313379ebbe7SSepherosa Ziehau 	ret_val = e1000_mng_enable_host_if_generic(hw);
3144be59a01SSepherosa Ziehau 	if (ret_val)
3159c80d176SSepherosa Ziehau 		return ret_val;
3164be59a01SSepherosa Ziehau 
3174be59a01SSepherosa Ziehau 	/* Populate the host interface with the contents of "buffer". */
318379ebbe7SSepherosa Ziehau 	ret_val = e1000_mng_host_if_write_generic(hw, buffer, length,
3194be59a01SSepherosa Ziehau 						  sizeof(hdr), &(hdr.checksum));
3204be59a01SSepherosa Ziehau 	if (ret_val)
3214be59a01SSepherosa Ziehau 		return ret_val;
3224be59a01SSepherosa Ziehau 
3234be59a01SSepherosa Ziehau 	/* Write the manageability command header */
324379ebbe7SSepherosa Ziehau 	ret_val = e1000_mng_write_cmd_header_generic(hw, &hdr);
3254be59a01SSepherosa Ziehau 	if (ret_val)
3264be59a01SSepherosa Ziehau 		return ret_val;
3274be59a01SSepherosa Ziehau 
3284be59a01SSepherosa Ziehau 	/* Tell the ARC a new command is pending. */
3294be59a01SSepherosa Ziehau 	hicr = E1000_READ_REG(hw, E1000_HICR);
3304be59a01SSepherosa Ziehau 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
3314be59a01SSepherosa Ziehau 
3324be59a01SSepherosa Ziehau 	return E1000_SUCCESS;
3339c80d176SSepherosa Ziehau }
3349c80d176SSepherosa Ziehau 
3359c80d176SSepherosa Ziehau /**
3366a5a645eSSepherosa Ziehau  *  e1000_enable_mng_pass_thru - Check if management passthrough is needed
3379c80d176SSepherosa Ziehau  *  @hw: pointer to the HW structure
3389c80d176SSepherosa Ziehau  *
3396a5a645eSSepherosa Ziehau  *  Verifies the hardware needs to leave interface enabled so that frames can
3406a5a645eSSepherosa Ziehau  *  be directed to and from the management interface.
3419c80d176SSepherosa Ziehau  **/
e1000_enable_mng_pass_thru(struct e1000_hw * hw)3429c80d176SSepherosa Ziehau bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
3439c80d176SSepherosa Ziehau {
3449c80d176SSepherosa Ziehau 	u32 manc;
3459c80d176SSepherosa Ziehau 	u32 fwsm, factps;
3469c80d176SSepherosa Ziehau 
3479c80d176SSepherosa Ziehau 	DEBUGFUNC("e1000_enable_mng_pass_thru");
3489c80d176SSepherosa Ziehau 
3499c80d176SSepherosa Ziehau 	if (!hw->mac.asf_firmware_present)
3504be59a01SSepherosa Ziehau 		return FALSE;
3519c80d176SSepherosa Ziehau 
3529c80d176SSepherosa Ziehau 	manc = E1000_READ_REG(hw, E1000_MANC);
3539c80d176SSepherosa Ziehau 
3546a5a645eSSepherosa Ziehau 	if (!(manc & E1000_MANC_RCV_TCO_EN))
3554be59a01SSepherosa Ziehau 		return FALSE;
3569c80d176SSepherosa Ziehau 
3576a5a645eSSepherosa Ziehau 	if (hw->mac.has_fwsm) {
3589c80d176SSepherosa Ziehau 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
3599c80d176SSepherosa Ziehau 		factps = E1000_READ_REG(hw, E1000_FACTPS);
3609c80d176SSepherosa Ziehau 
3619c80d176SSepherosa Ziehau 		if (!(factps & E1000_FACTPS_MNGCG) &&
3629c80d176SSepherosa Ziehau 		    ((fwsm & E1000_FWSM_MODE_MASK) ==
3634be59a01SSepherosa Ziehau 		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)))
3644be59a01SSepherosa Ziehau 			return TRUE;
3656a5a645eSSepherosa Ziehau 	} else if ((hw->mac.type == e1000_82574) ||
3666a5a645eSSepherosa Ziehau 		   (hw->mac.type == e1000_82583)) {
3676a5a645eSSepherosa Ziehau 		u16 data;
3684765c386SMichael Neumann 		s32 ret_val;
3696a5a645eSSepherosa Ziehau 
3706a5a645eSSepherosa Ziehau 		factps = E1000_READ_REG(hw, E1000_FACTPS);
3714765c386SMichael Neumann 		ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
3724765c386SMichael Neumann 		if (ret_val)
3734765c386SMichael Neumann 			return FALSE;
3746a5a645eSSepherosa Ziehau 
3756a5a645eSSepherosa Ziehau 		if (!(factps & E1000_FACTPS_MNGCG) &&
3766a5a645eSSepherosa Ziehau 		    ((data & E1000_NVM_INIT_CTRL2_MNGM) ==
3774be59a01SSepherosa Ziehau 		     (e1000_mng_mode_pt << 13)))
3784be59a01SSepherosa Ziehau 			return TRUE;
3796a5a645eSSepherosa Ziehau 	} else if ((manc & E1000_MANC_SMBUS_EN) &&
3806a5a645eSSepherosa Ziehau 		   !(manc & E1000_MANC_ASF_EN)) {
3814be59a01SSepherosa Ziehau 		return TRUE;
3829c80d176SSepherosa Ziehau 	}
3839c80d176SSepherosa Ziehau 
3844be59a01SSepherosa Ziehau 	return FALSE;
3859c80d176SSepherosa Ziehau }
3869c80d176SSepherosa Ziehau 
38762583d18SSepherosa Ziehau /**
38862583d18SSepherosa Ziehau  *  e1000_host_interface_command - Writes buffer to host interface
38962583d18SSepherosa Ziehau  *  @hw: pointer to the HW structure
39062583d18SSepherosa Ziehau  *  @buffer: contains a command to write
39162583d18SSepherosa Ziehau  *  @length: the byte length of the buffer, must be multiple of 4 bytes
39262583d18SSepherosa Ziehau  *
39362583d18SSepherosa Ziehau  *  Writes a buffer to the Host Interface.  Upon success, returns E1000_SUCCESS
39462583d18SSepherosa Ziehau  *  else returns E1000_ERR_HOST_INTERFACE_COMMAND.
39562583d18SSepherosa Ziehau  **/
e1000_host_interface_command(struct e1000_hw * hw,u8 * buffer,u32 length)39662583d18SSepherosa Ziehau s32 e1000_host_interface_command(struct e1000_hw *hw, u8 *buffer, u32 length)
39762583d18SSepherosa Ziehau {
39862583d18SSepherosa Ziehau 	u32 hicr, i;
39962583d18SSepherosa Ziehau 
40062583d18SSepherosa Ziehau 	DEBUGFUNC("e1000_host_interface_command");
40162583d18SSepherosa Ziehau 
40262583d18SSepherosa Ziehau 	if (!(hw->mac.arc_subsystem_valid)) {
40362583d18SSepherosa Ziehau 		DEBUGOUT("Hardware doesn't support host interface command.\n");
4044be59a01SSepherosa Ziehau 		return E1000_SUCCESS;
40562583d18SSepherosa Ziehau 	}
40662583d18SSepherosa Ziehau 
40762583d18SSepherosa Ziehau 	if (!hw->mac.asf_firmware_present) {
40862583d18SSepherosa Ziehau 		DEBUGOUT("Firmware is not present.\n");
4094be59a01SSepherosa Ziehau 		return E1000_SUCCESS;
41062583d18SSepherosa Ziehau 	}
41162583d18SSepherosa Ziehau 
41262583d18SSepherosa Ziehau 	if (length == 0 || length & 0x3 ||
41362583d18SSepherosa Ziehau 	    length > E1000_HI_MAX_BLOCK_BYTE_LENGTH) {
41462583d18SSepherosa Ziehau 		DEBUGOUT("Buffer length failure.\n");
4154be59a01SSepherosa Ziehau 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
41662583d18SSepherosa Ziehau 	}
41762583d18SSepherosa Ziehau 
41862583d18SSepherosa Ziehau 	/* Check that the host interface is enabled. */
41962583d18SSepherosa Ziehau 	hicr = E1000_READ_REG(hw, E1000_HICR);
4204be59a01SSepherosa Ziehau 	if (!(hicr & E1000_HICR_EN)) {
42162583d18SSepherosa Ziehau 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
4224be59a01SSepherosa Ziehau 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
42362583d18SSepherosa Ziehau 	}
42462583d18SSepherosa Ziehau 
42562583d18SSepherosa Ziehau 	/* Calculate length in DWORDs */
42662583d18SSepherosa Ziehau 	length >>= 2;
42762583d18SSepherosa Ziehau 
428379ebbe7SSepherosa Ziehau 	/* The device driver writes the relevant command block
42962583d18SSepherosa Ziehau 	 * into the ram area.
43062583d18SSepherosa Ziehau 	 */
43162583d18SSepherosa Ziehau 	for (i = 0; i < length; i++)
4324be59a01SSepherosa Ziehau 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
43362583d18SSepherosa Ziehau 					    *((u32 *)buffer + i));
43462583d18SSepherosa Ziehau 
43562583d18SSepherosa Ziehau 	/* Setting this bit tells the ARC that a new command is pending. */
43662583d18SSepherosa Ziehau 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
43762583d18SSepherosa Ziehau 
43862583d18SSepherosa Ziehau 	for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
43962583d18SSepherosa Ziehau 		hicr = E1000_READ_REG(hw, E1000_HICR);
44062583d18SSepherosa Ziehau 		if (!(hicr & E1000_HICR_C))
44162583d18SSepherosa Ziehau 			break;
44262583d18SSepherosa Ziehau 		msec_delay(1);
44362583d18SSepherosa Ziehau 	}
44462583d18SSepherosa Ziehau 
44562583d18SSepherosa Ziehau 	/* Check command successful completion. */
44662583d18SSepherosa Ziehau 	if (i == E1000_HI_COMMAND_TIMEOUT ||
44762583d18SSepherosa Ziehau 	    (!(E1000_READ_REG(hw, E1000_HICR) & E1000_HICR_SV))) {
44862583d18SSepherosa Ziehau 		DEBUGOUT("Command has failed with no status valid.\n");
4494be59a01SSepherosa Ziehau 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
45062583d18SSepherosa Ziehau 	}
45162583d18SSepherosa Ziehau 
45262583d18SSepherosa Ziehau 	for (i = 0; i < length; i++)
45362583d18SSepherosa Ziehau 		*((u32 *)buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
45462583d18SSepherosa Ziehau 								  E1000_HOST_IF,
45562583d18SSepherosa Ziehau 								  i);
45662583d18SSepherosa Ziehau 
4574be59a01SSepherosa Ziehau 	return E1000_SUCCESS;
45862583d18SSepherosa Ziehau }
4594be59a01SSepherosa Ziehau /**
4604be59a01SSepherosa Ziehau  *  e1000_load_firmware - Writes proxy FW code buffer to host interface
4614be59a01SSepherosa Ziehau  *                        and execute.
4624be59a01SSepherosa Ziehau  *  @hw: pointer to the HW structure
4634be59a01SSepherosa Ziehau  *  @buffer: contains a firmware to write
4644be59a01SSepherosa Ziehau  *  @length: the byte length of the buffer, must be multiple of 4 bytes
4654be59a01SSepherosa Ziehau  *
4664be59a01SSepherosa Ziehau  *  Upon success returns E1000_SUCCESS, returns E1000_ERR_CONFIG if not enabled
4674be59a01SSepherosa Ziehau  *  in HW else returns E1000_ERR_HOST_INTERFACE_COMMAND.
4684be59a01SSepherosa Ziehau  **/
e1000_load_firmware(struct e1000_hw * hw,u8 * buffer,u32 length)4694be59a01SSepherosa Ziehau s32 e1000_load_firmware(struct e1000_hw *hw, u8 *buffer, u32 length)
4704be59a01SSepherosa Ziehau {
4714be59a01SSepherosa Ziehau 	u32 hicr, hibba, fwsm, icr, i;
4724be59a01SSepherosa Ziehau 
4734be59a01SSepherosa Ziehau 	DEBUGFUNC("e1000_load_firmware");
4744be59a01SSepherosa Ziehau 
4754be59a01SSepherosa Ziehau 	if (hw->mac.type < e1000_i210) {
4764be59a01SSepherosa Ziehau 		DEBUGOUT("Hardware doesn't support loading FW by the driver\n");
4774be59a01SSepherosa Ziehau 		return -E1000_ERR_CONFIG;
4784be59a01SSepherosa Ziehau 	}
4794be59a01SSepherosa Ziehau 
4804be59a01SSepherosa Ziehau 	/* Check that the host interface is enabled. */
4814be59a01SSepherosa Ziehau 	hicr = E1000_READ_REG(hw, E1000_HICR);
4824be59a01SSepherosa Ziehau 	if (!(hicr & E1000_HICR_EN)) {
4834be59a01SSepherosa Ziehau 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
4844be59a01SSepherosa Ziehau 		return -E1000_ERR_CONFIG;
4854be59a01SSepherosa Ziehau 	}
4864be59a01SSepherosa Ziehau 	if (!(hicr & E1000_HICR_MEMORY_BASE_EN)) {
4874be59a01SSepherosa Ziehau 		DEBUGOUT("E1000_HICR_MEMORY_BASE_EN bit disabled.\n");
4884be59a01SSepherosa Ziehau 		return -E1000_ERR_CONFIG;
4894be59a01SSepherosa Ziehau 	}
4904be59a01SSepherosa Ziehau 
4914be59a01SSepherosa Ziehau 	if (length == 0 || length & 0x3 || length > E1000_HI_FW_MAX_LENGTH) {
4924be59a01SSepherosa Ziehau 		DEBUGOUT("Buffer length failure.\n");
4934be59a01SSepherosa Ziehau 		return -E1000_ERR_INVALID_ARGUMENT;
4944be59a01SSepherosa Ziehau 	}
4954be59a01SSepherosa Ziehau 
4964be59a01SSepherosa Ziehau 	/* Clear notification from ROM-FW by reading ICR register */
4974be59a01SSepherosa Ziehau 	icr = E1000_READ_REG(hw, E1000_ICR_V2);
4984be59a01SSepherosa Ziehau 
4994be59a01SSepherosa Ziehau 	/* Reset ROM-FW */
5004be59a01SSepherosa Ziehau 	hicr = E1000_READ_REG(hw, E1000_HICR);
5014be59a01SSepherosa Ziehau 	hicr |= E1000_HICR_FW_RESET_ENABLE;
5024be59a01SSepherosa Ziehau 	E1000_WRITE_REG(hw, E1000_HICR, hicr);
5034be59a01SSepherosa Ziehau 	hicr |= E1000_HICR_FW_RESET;
5044be59a01SSepherosa Ziehau 	E1000_WRITE_REG(hw, E1000_HICR, hicr);
5054be59a01SSepherosa Ziehau 	E1000_WRITE_FLUSH(hw);
5064be59a01SSepherosa Ziehau 
5074be59a01SSepherosa Ziehau 	/* Wait till MAC notifies about its readiness after ROM-FW reset */
5084be59a01SSepherosa Ziehau 	for (i = 0; i < (E1000_HI_COMMAND_TIMEOUT * 2); i++) {
5094be59a01SSepherosa Ziehau 		icr = E1000_READ_REG(hw, E1000_ICR_V2);
5104be59a01SSepherosa Ziehau 		if (icr & E1000_ICR_MNG)
5114be59a01SSepherosa Ziehau 			break;
5124be59a01SSepherosa Ziehau 		msec_delay(1);
5134be59a01SSepherosa Ziehau 	}
5144be59a01SSepherosa Ziehau 
5154be59a01SSepherosa Ziehau 	/* Check for timeout */
5164be59a01SSepherosa Ziehau 	if (i == E1000_HI_COMMAND_TIMEOUT) {
5174be59a01SSepherosa Ziehau 		DEBUGOUT("FW reset failed.\n");
5184be59a01SSepherosa Ziehau 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
5194be59a01SSepherosa Ziehau 	}
5204be59a01SSepherosa Ziehau 
5214be59a01SSepherosa Ziehau 	/* Wait till MAC is ready to accept new FW code */
5224be59a01SSepherosa Ziehau 	for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
5234be59a01SSepherosa Ziehau 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
5244be59a01SSepherosa Ziehau 		if ((fwsm & E1000_FWSM_FW_VALID) &&
5254be59a01SSepherosa Ziehau 		    ((fwsm & E1000_FWSM_MODE_MASK) >> E1000_FWSM_MODE_SHIFT ==
5264be59a01SSepherosa Ziehau 		    E1000_FWSM_HI_EN_ONLY_MODE))
5274be59a01SSepherosa Ziehau 			break;
5284be59a01SSepherosa Ziehau 		msec_delay(1);
5294be59a01SSepherosa Ziehau 	}
5304be59a01SSepherosa Ziehau 
5314be59a01SSepherosa Ziehau 	/* Check for timeout */
5324be59a01SSepherosa Ziehau 	if (i == E1000_HI_COMMAND_TIMEOUT) {
5334be59a01SSepherosa Ziehau 		DEBUGOUT("FW reset failed.\n");
5344be59a01SSepherosa Ziehau 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
5354be59a01SSepherosa Ziehau 	}
5364be59a01SSepherosa Ziehau 
5374be59a01SSepherosa Ziehau 	/* Calculate length in DWORDs */
5384be59a01SSepherosa Ziehau 	length >>= 2;
5394be59a01SSepherosa Ziehau 
540379ebbe7SSepherosa Ziehau 	/* The device driver writes the relevant FW code block
5414be59a01SSepherosa Ziehau 	 * into the ram area in DWORDs via 1kB ram addressing window.
5424be59a01SSepherosa Ziehau 	 */
5434be59a01SSepherosa Ziehau 	for (i = 0; i < length; i++) {
5444be59a01SSepherosa Ziehau 		if (!(i % E1000_HI_FW_BLOCK_DWORD_LENGTH)) {
5454be59a01SSepherosa Ziehau 			/* Point to correct 1kB ram window */
5464be59a01SSepherosa Ziehau 			hibba = E1000_HI_FW_BASE_ADDRESS +
5474be59a01SSepherosa Ziehau 				((E1000_HI_FW_BLOCK_DWORD_LENGTH << 2) *
5484be59a01SSepherosa Ziehau 				(i / E1000_HI_FW_BLOCK_DWORD_LENGTH));
5494be59a01SSepherosa Ziehau 
5504be59a01SSepherosa Ziehau 			E1000_WRITE_REG(hw, E1000_HIBBA, hibba);
5514be59a01SSepherosa Ziehau 		}
5524be59a01SSepherosa Ziehau 
5534be59a01SSepherosa Ziehau 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
5544be59a01SSepherosa Ziehau 					    i % E1000_HI_FW_BLOCK_DWORD_LENGTH,
5554be59a01SSepherosa Ziehau 					    *((u32 *)buffer + i));
5564be59a01SSepherosa Ziehau 	}
5574be59a01SSepherosa Ziehau 
5584be59a01SSepherosa Ziehau 	/* Setting this bit tells the ARC that a new FW is ready to execute. */
5594be59a01SSepherosa Ziehau 	hicr = E1000_READ_REG(hw, E1000_HICR);
5604be59a01SSepherosa Ziehau 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
5614be59a01SSepherosa Ziehau 
5624be59a01SSepherosa Ziehau 	for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
5634be59a01SSepherosa Ziehau 		hicr = E1000_READ_REG(hw, E1000_HICR);
5644be59a01SSepherosa Ziehau 		if (!(hicr & E1000_HICR_C))
5654be59a01SSepherosa Ziehau 			break;
5664be59a01SSepherosa Ziehau 		msec_delay(1);
5674be59a01SSepherosa Ziehau 	}
5684be59a01SSepherosa Ziehau 
5694be59a01SSepherosa Ziehau 	/* Check for successful FW start. */
5704be59a01SSepherosa Ziehau 	if (i == E1000_HI_COMMAND_TIMEOUT) {
5714be59a01SSepherosa Ziehau 		DEBUGOUT("New FW did not start within timeout period.\n");
5724be59a01SSepherosa Ziehau 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
5734be59a01SSepherosa Ziehau 	}
5744be59a01SSepherosa Ziehau 
5754be59a01SSepherosa Ziehau 	return E1000_SUCCESS;
5764be59a01SSepherosa Ziehau }
5774be59a01SSepherosa Ziehau 
57862583d18SSepherosa Ziehau 
579