15779Sxy150489 /* 25779Sxy150489 * CDDL HEADER START 35779Sxy150489 * 4*8571SChenlu.Chen@Sun.COM * Copyright(c) 2007-2009 Intel Corporation. All rights reserved. 55779Sxy150489 * The contents of this file are subject to the terms of the 65779Sxy150489 * Common Development and Distribution License (the "License"). 75779Sxy150489 * You may not use this file except in compliance with the License. 85779Sxy150489 * 95779Sxy150489 * You can obtain a copy of the license at: 105779Sxy150489 * http://www.opensolaris.org/os/licensing. 115779Sxy150489 * See the License for the specific language governing permissions 125779Sxy150489 * and limitations under the License. 135779Sxy150489 * 145779Sxy150489 * When using or redistributing this file, you may do so under the 155779Sxy150489 * License only. No other modification of this header is permitted. 165779Sxy150489 * 175779Sxy150489 * If applicable, add the following below this CDDL HEADER, with the 185779Sxy150489 * fields enclosed by brackets "[]" replaced with your own identifying 195779Sxy150489 * information: Portions Copyright [yyyy] [name of copyright owner] 205779Sxy150489 * 215779Sxy150489 * CDDL HEADER END 225779Sxy150489 */ 235779Sxy150489 245779Sxy150489 /* 25*8571SChenlu.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 265779Sxy150489 * Use is subject to license terms of the CDDL. 275779Sxy150489 */ 285779Sxy150489 29*8571SChenlu.Chen@Sun.COM /* IntelVersion: 1.27 v2008-10-7 */ 305779Sxy150489 315779Sxy150489 #include "igb_api.h" 325779Sxy150489 335779Sxy150489 static u8 e1000_calculate_checksum(u8 *buffer, u32 length); 345779Sxy150489 355779Sxy150489 /* 365779Sxy150489 * e1000_calculate_checksum - Calculate checksum for buffer 375779Sxy150489 * @buffer: pointer to EEPROM 385779Sxy150489 * @length: size of EEPROM to calculate a checksum for 395779Sxy150489 * 405779Sxy150489 * Calculates the checksum for some buffer on a specified length. The 415779Sxy150489 * checksum calculated is returned. 425779Sxy150489 */ 435779Sxy150489 static u8 e1000_calculate_checksum(u8 *buffer, u32 length) 445779Sxy150489 { 455779Sxy150489 u32 i; 465779Sxy150489 u8 sum = 0; 475779Sxy150489 485779Sxy150489 DEBUGFUNC("e1000_calculate_checksum"); 495779Sxy150489 505779Sxy150489 if (!buffer) 515779Sxy150489 return (0); 525779Sxy150489 535779Sxy150489 for (i = 0; i < length; i++) 545779Sxy150489 sum += buffer[i]; 555779Sxy150489 565779Sxy150489 return (u8) (0 - sum); 575779Sxy150489 } 585779Sxy150489 595779Sxy150489 /* 605779Sxy150489 * e1000_mng_enable_host_if_generic - Checks host interface is enabled 615779Sxy150489 * @hw: pointer to the HW structure 625779Sxy150489 * 635779Sxy150489 * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND 645779Sxy150489 * 65*8571SChenlu.Chen@Sun.COM * This function checks whether the HOST IF is enabled for command operation 665779Sxy150489 * and also checks whether the previous command is completed. It busy waits 675779Sxy150489 * in case of previous command is not completed. 685779Sxy150489 */ 695779Sxy150489 s32 705779Sxy150489 e1000_mng_enable_host_if_generic(struct e1000_hw *hw) 715779Sxy150489 { 725779Sxy150489 u32 hicr; 735779Sxy150489 s32 ret_val = E1000_SUCCESS; 745779Sxy150489 u8 i; 755779Sxy150489 765779Sxy150489 DEBUGFUNC("e1000_mng_enable_host_if_generic"); 775779Sxy150489 785779Sxy150489 /* Check that the host interface is enabled. */ 795779Sxy150489 hicr = E1000_READ_REG(hw, E1000_HICR); 805779Sxy150489 if ((hicr & E1000_HICR_EN) == 0) { 815779Sxy150489 DEBUGOUT("E1000_HOST_EN bit disabled.\n"); 825779Sxy150489 ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; 835779Sxy150489 goto out; 845779Sxy150489 } 855779Sxy150489 /* check the previous command is completed */ 865779Sxy150489 for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { 875779Sxy150489 hicr = E1000_READ_REG(hw, E1000_HICR); 885779Sxy150489 if (!(hicr & E1000_HICR_C)) 895779Sxy150489 break; 905779Sxy150489 msec_delay_irq(1); 915779Sxy150489 } 925779Sxy150489 935779Sxy150489 if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { 945779Sxy150489 DEBUGOUT("Previous command timeout failed .\n"); 955779Sxy150489 ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; 965779Sxy150489 goto out; 975779Sxy150489 } 985779Sxy150489 995779Sxy150489 out: 1005779Sxy150489 return (ret_val); 1015779Sxy150489 } 1025779Sxy150489 1035779Sxy150489 /* 104*8571SChenlu.Chen@Sun.COM * e1000_check_mng_mode_generic - Generic check management mode 1055779Sxy150489 * @hw: pointer to the HW structure 1065779Sxy150489 * 1075779Sxy150489 * Reads the firmware semaphore register and returns true (>0) if 1085779Sxy150489 * manageability is enabled, else false (0). 1095779Sxy150489 */ 1105779Sxy150489 bool 1115779Sxy150489 e1000_check_mng_mode_generic(struct e1000_hw *hw) 1125779Sxy150489 { 1135779Sxy150489 u32 fwsm; 1145779Sxy150489 1155779Sxy150489 DEBUGFUNC("e1000_check_mng_mode_generic"); 1165779Sxy150489 1175779Sxy150489 fwsm = E1000_READ_REG(hw, E1000_FWSM); 1185779Sxy150489 1195779Sxy150489 return ((fwsm & E1000_FWSM_MODE_MASK) == 1205779Sxy150489 (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 1215779Sxy150489 } 1225779Sxy150489 1235779Sxy150489 /* 1245779Sxy150489 * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX 1255779Sxy150489 * @hw: pointer to the HW structure 1265779Sxy150489 * 1275779Sxy150489 * Enables packet filtering on transmit packets if manageability is enabled 1285779Sxy150489 * and host interface is enabled. 1295779Sxy150489 */ 1305779Sxy150489 bool 1315779Sxy150489 e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) 1325779Sxy150489 { 1335779Sxy150489 struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; 1345779Sxy150489 u32 *buffer = (u32 *)&hw->mng_cookie; 1355779Sxy150489 u32 offset; 1365779Sxy150489 s32 ret_val, hdr_csum, csum; 1375779Sxy150489 u8 i, len; 138*8571SChenlu.Chen@Sun.COM bool tx_filter = true; 1395779Sxy150489 1405779Sxy150489 DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic"); 1415779Sxy150489 1425779Sxy150489 /* No manageability, no filtering */ 143*8571SChenlu.Chen@Sun.COM if (!hw->mac.ops.check_mng_mode(hw)) { 144*8571SChenlu.Chen@Sun.COM tx_filter = false; 1455779Sxy150489 goto out; 1465779Sxy150489 } 1475779Sxy150489 1485779Sxy150489 /* 1495779Sxy150489 * If we can't read from the host interface for whatever 1505779Sxy150489 * reason, disable filtering. 1515779Sxy150489 */ 152*8571SChenlu.Chen@Sun.COM ret_val = hw->mac.ops.mng_enable_host_if(hw); 1535779Sxy150489 if (ret_val != E1000_SUCCESS) { 154*8571SChenlu.Chen@Sun.COM tx_filter = false; 1555779Sxy150489 goto out; 1565779Sxy150489 } 1575779Sxy150489 1585779Sxy150489 /* Read in the header. Length and offset are in dwords. */ 1595779Sxy150489 len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; 1605779Sxy150489 offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; 1615779Sxy150489 for (i = 0; i < len; i++) { 1625779Sxy150489 *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, 1635779Sxy150489 E1000_HOST_IF, offset + i); 1645779Sxy150489 } 1655779Sxy150489 hdr_csum = hdr->checksum; 1665779Sxy150489 hdr->checksum = 0; 1675779Sxy150489 csum = e1000_calculate_checksum((u8 *)hdr, 1685779Sxy150489 E1000_MNG_DHCP_COOKIE_LENGTH); 1695779Sxy150489 /* 1705779Sxy150489 * If either the checksums or signature don't match, then 1715779Sxy150489 * the cookie area isn't considered valid, in which case we 1725779Sxy150489 * take the safe route of assuming Tx filtering is enabled. 1735779Sxy150489 */ 1745779Sxy150489 if (hdr_csum != csum) 1755779Sxy150489 goto out; 1765779Sxy150489 if (hdr->signature != E1000_IAMT_SIGNATURE) 1775779Sxy150489 goto out; 1785779Sxy150489 1795779Sxy150489 /* Cookie area is valid, make the final check for filtering. */ 1805779Sxy150489 if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) 181*8571SChenlu.Chen@Sun.COM tx_filter = false; 1825779Sxy150489 1835779Sxy150489 out: 1845779Sxy150489 hw->mac.tx_pkt_filtering = tx_filter; 1855779Sxy150489 return (tx_filter); 1865779Sxy150489 } 1875779Sxy150489 1885779Sxy150489 /* 1895779Sxy150489 * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface 1905779Sxy150489 * @hw: pointer to the HW structure 1915779Sxy150489 * @buffer: pointer to the host interface 1925779Sxy150489 * @length: size of the buffer 1935779Sxy150489 * 1945779Sxy150489 * Writes the DHCP information to the host interface. 1955779Sxy150489 */ 1965779Sxy150489 s32 1975779Sxy150489 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer, 1985779Sxy150489 u16 length) 1995779Sxy150489 { 2005779Sxy150489 struct e1000_host_mng_command_header hdr; 2015779Sxy150489 s32 ret_val; 2025779Sxy150489 u32 hicr; 2035779Sxy150489 2045779Sxy150489 DEBUGFUNC("e1000_mng_write_dhcp_info_generic"); 2055779Sxy150489 2065779Sxy150489 hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; 2075779Sxy150489 hdr.command_length = length; 2085779Sxy150489 hdr.reserved1 = 0; 2095779Sxy150489 hdr.reserved2 = 0; 2105779Sxy150489 hdr.checksum = 0; 2115779Sxy150489 2125779Sxy150489 /* Enable the host interface */ 213*8571SChenlu.Chen@Sun.COM ret_val = hw->mac.ops.mng_enable_host_if(hw); 2145779Sxy150489 if (ret_val) 2155779Sxy150489 goto out; 2165779Sxy150489 2175779Sxy150489 /* Populate the host interface with the contents of "buffer". */ 218*8571SChenlu.Chen@Sun.COM ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length, 2195779Sxy150489 sizeof (hdr), &(hdr.checksum)); 2205779Sxy150489 if (ret_val) 2215779Sxy150489 goto out; 2225779Sxy150489 2235779Sxy150489 /* Write the manageability command header */ 224*8571SChenlu.Chen@Sun.COM ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr); 2255779Sxy150489 if (ret_val) 2265779Sxy150489 goto out; 2275779Sxy150489 2285779Sxy150489 /* Tell the ARC a new command is pending. */ 2295779Sxy150489 hicr = E1000_READ_REG(hw, E1000_HICR); 2305779Sxy150489 E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C); 2315779Sxy150489 2325779Sxy150489 out: 2335779Sxy150489 return (ret_val); 2345779Sxy150489 } 2355779Sxy150489 2365779Sxy150489 /* 2375779Sxy150489 * e1000_mng_write_cmd_header_generic - Writes manageability command header 2385779Sxy150489 * @hw: pointer to the HW structure 2395779Sxy150489 * @hdr: pointer to the host interface command header 2405779Sxy150489 * 2415779Sxy150489 * Writes the command header after does the checksum calculation. 2425779Sxy150489 */ 2435779Sxy150489 s32 2445779Sxy150489 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw, 2455779Sxy150489 struct e1000_host_mng_command_header *hdr) 2465779Sxy150489 { 2475779Sxy150489 u16 i, length = sizeof (struct e1000_host_mng_command_header); 2485779Sxy150489 2495779Sxy150489 DEBUGFUNC("e1000_mng_write_cmd_header_generic"); 2505779Sxy150489 2515779Sxy150489 /* Write the whole command header structure with new checksum. */ 2525779Sxy150489 2535779Sxy150489 hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); 2545779Sxy150489 2555779Sxy150489 length >>= 2; 2565779Sxy150489 /* Write the relevant command block into the ram area. */ 2575779Sxy150489 for (i = 0; i < length; i++) { 2585779Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i, 2595779Sxy150489 *((u32 *)(uintptr_t)hdr + i)); 2605779Sxy150489 E1000_WRITE_FLUSH(hw); 2615779Sxy150489 } 2625779Sxy150489 2635779Sxy150489 return (E1000_SUCCESS); 2645779Sxy150489 } 2655779Sxy150489 2665779Sxy150489 /* 2675779Sxy150489 * e1000_mng_host_if_write_generic - Write to the manageability host interface 2685779Sxy150489 * @hw: pointer to the HW structure 2695779Sxy150489 * @buffer: pointer to the host interface buffer 2705779Sxy150489 * @length: size of the buffer 2715779Sxy150489 * @offset: location in the buffer to write to 2725779Sxy150489 * @sum: sum of the data (not checksum) 2735779Sxy150489 * 2745779Sxy150489 * This function writes the buffer content at the offset given on the host if. 2755779Sxy150489 * It also does alignment considerations to do the writes in most efficient 2765779Sxy150489 * way. Also fills up the sum of the buffer in *buffer parameter. 2775779Sxy150489 */ 2785779Sxy150489 s32 2795779Sxy150489 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, 2805779Sxy150489 u16 length, u16 offset, u8 *sum) 2815779Sxy150489 { 2825779Sxy150489 u8 *tmp; 2835779Sxy150489 u8 *bufptr = buffer; 2845779Sxy150489 u32 data = 0; 2855779Sxy150489 s32 ret_val = E1000_SUCCESS; 2865779Sxy150489 u16 remaining, i, j, prev_bytes; 2875779Sxy150489 2885779Sxy150489 DEBUGFUNC("e1000_mng_host_if_write_generic"); 2895779Sxy150489 2905779Sxy150489 /* sum = only sum of the data and it is not checksum */ 2915779Sxy150489 2925779Sxy150489 if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { 2935779Sxy150489 ret_val = -E1000_ERR_PARAM; 2945779Sxy150489 goto out; 2955779Sxy150489 } 2965779Sxy150489 2975779Sxy150489 tmp = (u8 *)&data; 2985779Sxy150489 prev_bytes = offset & 0x3; 2995779Sxy150489 offset >>= 2; 3005779Sxy150489 3015779Sxy150489 if (prev_bytes) { 3025779Sxy150489 data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset); 3035779Sxy150489 for (j = prev_bytes; j < sizeof (u32); j++) { 3045779Sxy150489 *(tmp + j) = *bufptr++; 3055779Sxy150489 *sum += *(tmp + j); 3065779Sxy150489 } 3075779Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data); 3085779Sxy150489 length -= j - prev_bytes; 3095779Sxy150489 offset++; 3105779Sxy150489 } 3115779Sxy150489 3125779Sxy150489 remaining = length & 0x3; 3135779Sxy150489 length -= remaining; 3145779Sxy150489 3155779Sxy150489 /* Calculate length in DWORDs */ 3165779Sxy150489 length >>= 2; 3175779Sxy150489 3185779Sxy150489 /* 3195779Sxy150489 * The device driver writes the relevant command block into the 3205779Sxy150489 * ram area. 3215779Sxy150489 */ 3225779Sxy150489 for (i = 0; i < length; i++) { 3235779Sxy150489 for (j = 0; j < sizeof (u32); j++) { 3245779Sxy150489 *(tmp + j) = *bufptr++; 3255779Sxy150489 *sum += *(tmp + j); 3265779Sxy150489 } 3275779Sxy150489 3285779Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, 3295779Sxy150489 offset + i, data); 3305779Sxy150489 } 3315779Sxy150489 if (remaining) { 3325779Sxy150489 for (j = 0; j < sizeof (u32); j++) { 3335779Sxy150489 if (j < remaining) 3345779Sxy150489 *(tmp + j) = *bufptr++; 3355779Sxy150489 else 3365779Sxy150489 *(tmp + j) = 0; 3375779Sxy150489 3385779Sxy150489 *sum += *(tmp + j); 3395779Sxy150489 } 3405779Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, 3415779Sxy150489 offset + i, data); 3425779Sxy150489 } 3435779Sxy150489 3445779Sxy150489 out: 3455779Sxy150489 return (ret_val); 3465779Sxy150489 } 3475779Sxy150489 3485779Sxy150489 /* 3495779Sxy150489 * e1000_enable_mng_pass_thru - Enable processing of ARP's 3505779Sxy150489 * @hw: pointer to the HW structure 3515779Sxy150489 * 3525779Sxy150489 * Verifies the hardware needs to allow ARPs to be processed by the host. 3535779Sxy150489 */ 3545779Sxy150489 bool 3555779Sxy150489 e1000_enable_mng_pass_thru(struct e1000_hw *hw) 3565779Sxy150489 { 3575779Sxy150489 u32 manc; 3585779Sxy150489 u32 fwsm, factps; 359*8571SChenlu.Chen@Sun.COM bool ret_val = false; 3605779Sxy150489 3615779Sxy150489 DEBUGFUNC("e1000_enable_mng_pass_thru"); 3625779Sxy150489 3635779Sxy150489 if (!hw->mac.asf_firmware_present) 3645779Sxy150489 goto out; 3655779Sxy150489 3665779Sxy150489 manc = E1000_READ_REG(hw, E1000_MANC); 3675779Sxy150489 3685779Sxy150489 if (!(manc & E1000_MANC_RCV_TCO_EN) || 3695779Sxy150489 !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) 3705779Sxy150489 goto out; 3715779Sxy150489 3725779Sxy150489 if (hw->mac.arc_subsystem_valid) { 3735779Sxy150489 fwsm = E1000_READ_REG(hw, E1000_FWSM); 3745779Sxy150489 factps = E1000_READ_REG(hw, E1000_FACTPS); 3755779Sxy150489 3765779Sxy150489 if (!(factps & E1000_FACTPS_MNGCG) && 3775779Sxy150489 ((fwsm & E1000_FWSM_MODE_MASK) == 3785779Sxy150489 (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { 379*8571SChenlu.Chen@Sun.COM ret_val = true; 3805779Sxy150489 goto out; 3815779Sxy150489 } 3825779Sxy150489 } else { 3835779Sxy150489 if ((manc & E1000_MANC_SMBUS_EN) && 3845779Sxy150489 !(manc & E1000_MANC_ASF_EN)) { 385*8571SChenlu.Chen@Sun.COM ret_val = true; 3865779Sxy150489 goto out; 3875779Sxy150489 } 3885779Sxy150489 } 3895779Sxy150489 3905779Sxy150489 out: 3915779Sxy150489 return (ret_val); 3925779Sxy150489 } 393