14919Sxy150489 /* 24919Sxy150489 * This file is provided under a CDDLv1 license. When using or 34919Sxy150489 * redistributing this file, you may do so under this license. 44919Sxy150489 * In redistributing this file this license must be included 54919Sxy150489 * and no other modification of this header file is permitted. 64919Sxy150489 * 74919Sxy150489 * CDDL LICENSE SUMMARY 84919Sxy150489 * 96735Scc210113 * Copyright(c) 1999 - 2008 Intel Corporation. All rights reserved. 104919Sxy150489 * 114919Sxy150489 * The contents of this file are subject to the terms of Version 124919Sxy150489 * 1.0 of the Common Development and Distribution License (the "License"). 134919Sxy150489 * 144919Sxy150489 * You should have received a copy of the License with this software. 154919Sxy150489 * You can obtain a copy of the License at 164919Sxy150489 * http://www.opensolaris.org/os/licensing. 174919Sxy150489 * See the License for the specific language governing permissions 184919Sxy150489 * and limitations under the License. 194919Sxy150489 */ 204919Sxy150489 214919Sxy150489 /* 226735Scc210113 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 234919Sxy150489 * Use is subject to license terms of the CDDLv1. 244919Sxy150489 */ 254919Sxy150489 264919Sxy150489 /* 276735Scc210113 * IntelVersion: 1.21 v2008-02-29 284919Sxy150489 */ 296735Scc210113 304919Sxy150489 #include "e1000_api.h" 314919Sxy150489 #include "e1000_manage.h" 324919Sxy150489 334919Sxy150489 static u8 e1000_calculate_checksum(u8 *buffer, u32 length); 344919Sxy150489 354919Sxy150489 /* 364919Sxy150489 * e1000_calculate_checksum - Calculate checksum for buffer 374919Sxy150489 * @buffer: pointer to EEPROM 384919Sxy150489 * @length: size of EEPROM to calculate a checksum for 394919Sxy150489 * 404919Sxy150489 * Calculates the checksum for some buffer on a specified length. The 414919Sxy150489 * checksum calculated is returned. 424919Sxy150489 */ 434919Sxy150489 static u8 444919Sxy150489 e1000_calculate_checksum(u8 *buffer, u32 length) 454919Sxy150489 { 464919Sxy150489 u32 i; 474919Sxy150489 u8 sum = 0; 484919Sxy150489 494919Sxy150489 DEBUGFUNC("e1000_calculate_checksum"); 504919Sxy150489 514919Sxy150489 if (!buffer) 524919Sxy150489 return (0); 534919Sxy150489 544919Sxy150489 for (i = 0; i < length; i++) 554919Sxy150489 sum += buffer[i]; 564919Sxy150489 574919Sxy150489 return (u8)(0 - sum); 584919Sxy150489 } 594919Sxy150489 604919Sxy150489 /* 614919Sxy150489 * e1000_mng_enable_host_if_generic - Checks host interface is enabled 624919Sxy150489 * @hw: pointer to the HW structure 634919Sxy150489 * 644919Sxy150489 * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND 654919Sxy150489 * 666735Scc210113 * This function checks whether the HOST IF is enabled for command operation 674919Sxy150489 * and also checks whether the previous command is completed. It busy waits 684919Sxy150489 * in case of previous command is not completed. 694919Sxy150489 */ 704919Sxy150489 s32 714919Sxy150489 e1000_mng_enable_host_if_generic(struct e1000_hw *hw) 724919Sxy150489 { 734919Sxy150489 u32 hicr; 744919Sxy150489 s32 ret_val = E1000_SUCCESS; 754919Sxy150489 u8 i; 764919Sxy150489 774919Sxy150489 DEBUGFUNC("e1000_mng_enable_host_if_generic"); 784919Sxy150489 794919Sxy150489 /* Check that the host interface is enabled. */ 804919Sxy150489 hicr = E1000_READ_REG(hw, E1000_HICR); 814919Sxy150489 if ((hicr & E1000_HICR_EN) == 0) { 824919Sxy150489 DEBUGOUT("E1000_HOST_EN bit disabled.\n"); 834919Sxy150489 ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; 844919Sxy150489 goto out; 854919Sxy150489 } 864919Sxy150489 /* check the previous command is completed */ 874919Sxy150489 for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { 884919Sxy150489 hicr = E1000_READ_REG(hw, E1000_HICR); 894919Sxy150489 if (!(hicr & E1000_HICR_C)) 904919Sxy150489 break; 914919Sxy150489 msec_delay_irq(1); 924919Sxy150489 } 934919Sxy150489 944919Sxy150489 if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { 954919Sxy150489 DEBUGOUT("Previous command timeout failed .\n"); 964919Sxy150489 ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; 974919Sxy150489 goto out; 984919Sxy150489 } 994919Sxy150489 out: 1004919Sxy150489 return (ret_val); 1014919Sxy150489 } 1024919Sxy150489 1034919Sxy150489 /* 1046735Scc210113 * e1000_check_mng_mode_generic - Generic check management mode 1054919Sxy150489 * @hw: pointer to the HW structure 1064919Sxy150489 * 1074919Sxy150489 * Reads the firmware semaphore register and returns true (>0) if 1084919Sxy150489 * manageability is enabled, else false (0). 1094919Sxy150489 */ 1106735Scc210113 bool 1114919Sxy150489 e1000_check_mng_mode_generic(struct e1000_hw *hw) 1124919Sxy150489 { 1134919Sxy150489 u32 fwsm; 1144919Sxy150489 1154919Sxy150489 DEBUGFUNC("e1000_check_mng_mode_generic"); 1164919Sxy150489 1174919Sxy150489 fwsm = E1000_READ_REG(hw, E1000_FWSM); 1184919Sxy150489 1194919Sxy150489 return ((fwsm & E1000_FWSM_MODE_MASK) == 1204919Sxy150489 (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 1214919Sxy150489 } 1224919Sxy150489 1234919Sxy150489 /* 1244919Sxy150489 * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX 1254919Sxy150489 * @hw: pointer to the HW structure 1264919Sxy150489 * 1274919Sxy150489 * Enables packet filtering on transmit packets if manageability is enabled 1284919Sxy150489 * and host interface is enabled. 1294919Sxy150489 */ 1306735Scc210113 bool 1314919Sxy150489 e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) 1324919Sxy150489 { 1334919Sxy150489 struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; 1344919Sxy150489 u32 *buffer = (u32 *)&hw->mng_cookie; 1354919Sxy150489 u32 offset; 1364919Sxy150489 s32 ret_val, hdr_csum, csum; 1374919Sxy150489 u8 i, len; 1386735Scc210113 bool tx_filter = TRUE; 1394919Sxy150489 1404919Sxy150489 DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic"); 1414919Sxy150489 1424919Sxy150489 /* No manageability, no filtering */ 1436735Scc210113 if (!hw->mac.ops.check_mng_mode(hw)) { 1444919Sxy150489 tx_filter = FALSE; 1454919Sxy150489 goto out; 1464919Sxy150489 } 1474919Sxy150489 1484919Sxy150489 /* 1494919Sxy150489 * If we can't read from the host interface for whatever reason, 1504919Sxy150489 * disable filtering. 1514919Sxy150489 */ 1526735Scc210113 ret_val = hw->mac.ops.mng_enable_host_if(hw); 1534919Sxy150489 if (ret_val != E1000_SUCCESS) { 1544919Sxy150489 tx_filter = FALSE; 1554919Sxy150489 goto out; 1564919Sxy150489 } 1574919Sxy150489 1584919Sxy150489 /* Read in the header. Length and offset are in dwords. */ 1594919Sxy150489 len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; 1604919Sxy150489 offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; 1614919Sxy150489 for (i = 0; i < len; i++) { 1624919Sxy150489 *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, 1634919Sxy150489 E1000_HOST_IF, 1644919Sxy150489 offset + i); 1654919Sxy150489 } 1664919Sxy150489 hdr_csum = hdr->checksum; 1674919Sxy150489 hdr->checksum = 0; 1684919Sxy150489 csum = e1000_calculate_checksum((u8 *)hdr, 1694919Sxy150489 E1000_MNG_DHCP_COOKIE_LENGTH); 1704919Sxy150489 /* 1714919Sxy150489 * If either the checksums or signature don't match, then the cookie 1724919Sxy150489 * area isn't considered valid, in which case we take the safe route 1734919Sxy150489 * of assuming Tx filtering is enabled. 1744919Sxy150489 */ 1754919Sxy150489 if (hdr_csum != csum) 1764919Sxy150489 goto out; 1774919Sxy150489 if (hdr->signature != E1000_IAMT_SIGNATURE) 1784919Sxy150489 goto out; 1794919Sxy150489 1804919Sxy150489 /* Cookie area is valid, make the final check for filtering. */ 1814919Sxy150489 if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) 1824919Sxy150489 tx_filter = FALSE; 1834919Sxy150489 1844919Sxy150489 out: 1854919Sxy150489 hw->mac.tx_pkt_filtering = tx_filter; 1864919Sxy150489 return (tx_filter); 1874919Sxy150489 } 1884919Sxy150489 1894919Sxy150489 /* 1904919Sxy150489 * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface 1914919Sxy150489 * @hw: pointer to the HW structure 1924919Sxy150489 * @buffer: pointer to the host interface 1934919Sxy150489 * @length: size of the buffer 1944919Sxy150489 * 1954919Sxy150489 * Writes the DHCP information to the host interface. 1964919Sxy150489 */ 1974919Sxy150489 s32 1984919Sxy150489 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer, 1994919Sxy150489 u16 length) 2004919Sxy150489 { 2014919Sxy150489 struct e1000_host_mng_command_header hdr; 2024919Sxy150489 s32 ret_val; 2034919Sxy150489 u32 hicr; 2044919Sxy150489 2054919Sxy150489 DEBUGFUNC("e1000_mng_write_dhcp_info_generic"); 2064919Sxy150489 2074919Sxy150489 hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; 2084919Sxy150489 hdr.command_length = length; 2094919Sxy150489 hdr.reserved1 = 0; 2104919Sxy150489 hdr.reserved2 = 0; 2114919Sxy150489 hdr.checksum = 0; 2124919Sxy150489 2134919Sxy150489 /* Enable the host interface */ 2146735Scc210113 ret_val = hw->mac.ops.mng_enable_host_if(hw); 2154919Sxy150489 if (ret_val) 2164919Sxy150489 goto out; 2174919Sxy150489 2184919Sxy150489 /* Populate the host interface with the contents of "buffer". */ 2196735Scc210113 ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length, 2204919Sxy150489 sizeof (hdr), &(hdr.checksum)); 2214919Sxy150489 if (ret_val) 2224919Sxy150489 goto out; 2234919Sxy150489 2244919Sxy150489 /* Write the manageability command header */ 2256735Scc210113 ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr); 2264919Sxy150489 if (ret_val) 2274919Sxy150489 goto out; 2284919Sxy150489 2294919Sxy150489 /* Tell the ARC a new command is pending. */ 2304919Sxy150489 hicr = E1000_READ_REG(hw, E1000_HICR); 2314919Sxy150489 E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C); 2324919Sxy150489 2334919Sxy150489 out: 2344919Sxy150489 return (ret_val); 2354919Sxy150489 } 2364919Sxy150489 2374919Sxy150489 /* 2384919Sxy150489 * e1000_mng_write_cmd_header_generic - Writes manageability command header 2394919Sxy150489 * @hw: pointer to the HW structure 2404919Sxy150489 * @hdr: pointer to the host interface command header 2414919Sxy150489 * 2424919Sxy150489 * Writes the command header after does the checksum calculation. 2434919Sxy150489 */ 2444919Sxy150489 s32 2454919Sxy150489 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw, 2464919Sxy150489 struct e1000_host_mng_command_header *hdr) 2474919Sxy150489 { 2484919Sxy150489 u16 i, length = sizeof (struct e1000_host_mng_command_header); 2494919Sxy150489 2504919Sxy150489 DEBUGFUNC("e1000_mng_write_cmd_header_generic"); 2514919Sxy150489 2524919Sxy150489 /* Write the whole command header structure with new checksum. */ 2534919Sxy150489 2544919Sxy150489 hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); 2554919Sxy150489 2564919Sxy150489 length >>= 2; 2574919Sxy150489 /* Write the relevant command block into the ram area. */ 2584919Sxy150489 for (i = 0; i < length; i++) { 2594919Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i, 260*7426SChenliang.Xu@Sun.COM *((u32 *)(uintptr_t)hdr + i)); 2614919Sxy150489 E1000_WRITE_FLUSH(hw); 2624919Sxy150489 } 2634919Sxy150489 2644919Sxy150489 return (E1000_SUCCESS); 2654919Sxy150489 } 2664919Sxy150489 2674919Sxy150489 /* 2686735Scc210113 * e1000_mng_host_if_write_generic - Write to the manageability host interface 2694919Sxy150489 * @hw: pointer to the HW structure 2704919Sxy150489 * @buffer: pointer to the host interface buffer 2714919Sxy150489 * @length: size of the buffer 2724919Sxy150489 * @offset: location in the buffer to write to 2734919Sxy150489 * @sum: sum of the data (not checksum) 2744919Sxy150489 * 2754919Sxy150489 * This function writes the buffer content at the offset given on the host if. 2764919Sxy150489 * It also does alignment considerations to do the writes in most efficient 2774919Sxy150489 * way. Also fills up the sum of the buffer in *buffer parameter. 2784919Sxy150489 */ 2794919Sxy150489 s32 2804919Sxy150489 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, 2814919Sxy150489 u16 length, u16 offset, u8 *sum) 2824919Sxy150489 { 2834919Sxy150489 u8 *tmp; 2844919Sxy150489 u8 *bufptr = buffer; 2854919Sxy150489 u32 data = 0; 2864919Sxy150489 s32 ret_val = E1000_SUCCESS; 2874919Sxy150489 u16 remaining, i, j, prev_bytes; 2884919Sxy150489 2894919Sxy150489 DEBUGFUNC("e1000_mng_host_if_write_generic"); 2904919Sxy150489 2914919Sxy150489 /* sum = only sum of the data and it is not checksum */ 2924919Sxy150489 2934919Sxy150489 if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { 2944919Sxy150489 ret_val = -E1000_ERR_PARAM; 2954919Sxy150489 goto out; 2964919Sxy150489 } 2974919Sxy150489 2984919Sxy150489 tmp = (u8 *)&data; 2994919Sxy150489 prev_bytes = offset & 0x3; 3004919Sxy150489 offset >>= 2; 3014919Sxy150489 3024919Sxy150489 if (prev_bytes) { 3034919Sxy150489 data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset); 3044919Sxy150489 for (j = prev_bytes; j < sizeof (u32); j++) { 3054919Sxy150489 *(tmp + j) = *bufptr++; 3064919Sxy150489 *sum += *(tmp + j); 3074919Sxy150489 } 3084919Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data); 3094919Sxy150489 length -= j - prev_bytes; 3104919Sxy150489 offset++; 3114919Sxy150489 } 3124919Sxy150489 3134919Sxy150489 remaining = length & 0x3; 3144919Sxy150489 length -= remaining; 3154919Sxy150489 3164919Sxy150489 /* Calculate length in DWORDs */ 3174919Sxy150489 length >>= 2; 3184919Sxy150489 3194919Sxy150489 /* 3204919Sxy150489 * The device driver writes the relevant command block into the ram 3214919Sxy150489 * area. 3224919Sxy150489 */ 3234919Sxy150489 for (i = 0; i < length; i++) { 3244919Sxy150489 for (j = 0; j < sizeof (u32); j++) { 3254919Sxy150489 *(tmp + j) = *bufptr++; 3264919Sxy150489 *sum += *(tmp + j); 3274919Sxy150489 } 3284919Sxy150489 3294919Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, 3304919Sxy150489 offset + i, data); 3314919Sxy150489 } 3324919Sxy150489 if (remaining) { 3334919Sxy150489 for (j = 0; j < sizeof (u32); j++) { 3344919Sxy150489 if (j < remaining) 3354919Sxy150489 *(tmp + j) = *bufptr++; 3364919Sxy150489 else 3374919Sxy150489 *(tmp + j) = 0; 3384919Sxy150489 3394919Sxy150489 *sum += *(tmp + j); 3404919Sxy150489 } 3414919Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, 3424919Sxy150489 offset + i, data); 3434919Sxy150489 } 3444919Sxy150489 out: 3454919Sxy150489 return (ret_val); 3464919Sxy150489 } 3474919Sxy150489 3484919Sxy150489 /* 3494919Sxy150489 * e1000_enable_mng_pass_thru - Enable processing of ARP's 3504919Sxy150489 * @hw: pointer to the HW structure 3514919Sxy150489 * 3524919Sxy150489 * Verifies the hardware needs to allow ARPs to be processed by the host. 3534919Sxy150489 */ 3546735Scc210113 bool 3554919Sxy150489 e1000_enable_mng_pass_thru(struct e1000_hw *hw) 3564919Sxy150489 { 3574919Sxy150489 u32 manc; 3584919Sxy150489 u32 fwsm, factps; 3596735Scc210113 bool ret_val = FALSE; 3604919Sxy150489 3614919Sxy150489 DEBUGFUNC("e1000_enable_mng_pass_thru"); 3624919Sxy150489 3634919Sxy150489 if (!hw->mac.asf_firmware_present) 3644919Sxy150489 goto out; 3654919Sxy150489 3664919Sxy150489 manc = E1000_READ_REG(hw, E1000_MANC); 3674919Sxy150489 3684919Sxy150489 if (!(manc & E1000_MANC_RCV_TCO_EN) || 3694919Sxy150489 !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) 3704919Sxy150489 goto out; 3714919Sxy150489 3724919Sxy150489 if (hw->mac.arc_subsystem_valid) { 3734919Sxy150489 fwsm = E1000_READ_REG(hw, E1000_FWSM); 3744919Sxy150489 factps = E1000_READ_REG(hw, E1000_FACTPS); 3754919Sxy150489 3764919Sxy150489 if (!(factps & E1000_FACTPS_MNGCG) && 3774919Sxy150489 ((fwsm & E1000_FWSM_MODE_MASK) == 3784919Sxy150489 (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { 3794919Sxy150489 ret_val = TRUE; 3804919Sxy150489 goto out; 3814919Sxy150489 } 3824919Sxy150489 } else { 3834919Sxy150489 if ((manc & E1000_MANC_SMBUS_EN) && 3844919Sxy150489 !(manc & E1000_MANC_ASF_EN)) { 3854919Sxy150489 ret_val = TRUE; 3864919Sxy150489 goto out; 3874919Sxy150489 } 3884919Sxy150489 } 3894919Sxy150489 3904919Sxy150489 out: 3914919Sxy150489 return (ret_val); 3924919Sxy150489 } 393