1*5779Sxy150489 /* 2*5779Sxy150489 * CDDL HEADER START 3*5779Sxy150489 * 4*5779Sxy150489 * Copyright(c) 2007-2008 Intel Corporation. All rights reserved. 5*5779Sxy150489 * The contents of this file are subject to the terms of the 6*5779Sxy150489 * Common Development and Distribution License (the "License"). 7*5779Sxy150489 * You may not use this file except in compliance with the License. 8*5779Sxy150489 * 9*5779Sxy150489 * You can obtain a copy of the license at: 10*5779Sxy150489 * http://www.opensolaris.org/os/licensing. 11*5779Sxy150489 * See the License for the specific language governing permissions 12*5779Sxy150489 * and limitations under the License. 13*5779Sxy150489 * 14*5779Sxy150489 * When using or redistributing this file, you may do so under the 15*5779Sxy150489 * License only. No other modification of this header is permitted. 16*5779Sxy150489 * 17*5779Sxy150489 * If applicable, add the following below this CDDL HEADER, with the 18*5779Sxy150489 * fields enclosed by brackets "[]" replaced with your own identifying 19*5779Sxy150489 * information: Portions Copyright [yyyy] [name of copyright owner] 20*5779Sxy150489 * 21*5779Sxy150489 * CDDL HEADER END 22*5779Sxy150489 */ 23*5779Sxy150489 24*5779Sxy150489 /* 25*5779Sxy150489 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 26*5779Sxy150489 * Use is subject to license terms of the CDDL. 27*5779Sxy150489 */ 28*5779Sxy150489 29*5779Sxy150489 #pragma ident "%Z%%M% %I% %E% SMI" 30*5779Sxy150489 31*5779Sxy150489 #include "igb_api.h" 32*5779Sxy150489 #include "igb_manage.h" 33*5779Sxy150489 34*5779Sxy150489 static u8 e1000_calculate_checksum(u8 *buffer, u32 length); 35*5779Sxy150489 36*5779Sxy150489 /* 37*5779Sxy150489 * e1000_calculate_checksum - Calculate checksum for buffer 38*5779Sxy150489 * @buffer: pointer to EEPROM 39*5779Sxy150489 * @length: size of EEPROM to calculate a checksum for 40*5779Sxy150489 * 41*5779Sxy150489 * Calculates the checksum for some buffer on a specified length. The 42*5779Sxy150489 * checksum calculated is returned. 43*5779Sxy150489 */ 44*5779Sxy150489 static u8 e1000_calculate_checksum(u8 *buffer, u32 length) 45*5779Sxy150489 { 46*5779Sxy150489 u32 i; 47*5779Sxy150489 u8 sum = 0; 48*5779Sxy150489 49*5779Sxy150489 DEBUGFUNC("e1000_calculate_checksum"); 50*5779Sxy150489 51*5779Sxy150489 if (!buffer) 52*5779Sxy150489 return (0); 53*5779Sxy150489 54*5779Sxy150489 for (i = 0; i < length; i++) 55*5779Sxy150489 sum += buffer[i]; 56*5779Sxy150489 57*5779Sxy150489 return (u8) (0 - sum); 58*5779Sxy150489 } 59*5779Sxy150489 60*5779Sxy150489 /* 61*5779Sxy150489 * e1000_mng_enable_host_if_generic - Checks host interface is enabled 62*5779Sxy150489 * @hw: pointer to the HW structure 63*5779Sxy150489 * 64*5779Sxy150489 * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND 65*5779Sxy150489 * 66*5779Sxy150489 * This function checks whether the HOST IF is enabled for command operaton 67*5779Sxy150489 * and also checks whether the previous command is completed. It busy waits 68*5779Sxy150489 * in case of previous command is not completed. 69*5779Sxy150489 */ 70*5779Sxy150489 s32 71*5779Sxy150489 e1000_mng_enable_host_if_generic(struct e1000_hw *hw) 72*5779Sxy150489 { 73*5779Sxy150489 u32 hicr; 74*5779Sxy150489 s32 ret_val = E1000_SUCCESS; 75*5779Sxy150489 u8 i; 76*5779Sxy150489 77*5779Sxy150489 DEBUGFUNC("e1000_mng_enable_host_if_generic"); 78*5779Sxy150489 79*5779Sxy150489 /* Check that the host interface is enabled. */ 80*5779Sxy150489 hicr = E1000_READ_REG(hw, E1000_HICR); 81*5779Sxy150489 if ((hicr & E1000_HICR_EN) == 0) { 82*5779Sxy150489 DEBUGOUT("E1000_HOST_EN bit disabled.\n"); 83*5779Sxy150489 ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; 84*5779Sxy150489 goto out; 85*5779Sxy150489 } 86*5779Sxy150489 /* check the previous command is completed */ 87*5779Sxy150489 for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { 88*5779Sxy150489 hicr = E1000_READ_REG(hw, E1000_HICR); 89*5779Sxy150489 if (!(hicr & E1000_HICR_C)) 90*5779Sxy150489 break; 91*5779Sxy150489 msec_delay_irq(1); 92*5779Sxy150489 } 93*5779Sxy150489 94*5779Sxy150489 if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { 95*5779Sxy150489 DEBUGOUT("Previous command timeout failed .\n"); 96*5779Sxy150489 ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; 97*5779Sxy150489 goto out; 98*5779Sxy150489 } 99*5779Sxy150489 100*5779Sxy150489 out: 101*5779Sxy150489 return (ret_val); 102*5779Sxy150489 } 103*5779Sxy150489 104*5779Sxy150489 /* 105*5779Sxy150489 * e1000_check_mng_mode_generic - Generic check managament mode 106*5779Sxy150489 * @hw: pointer to the HW structure 107*5779Sxy150489 * 108*5779Sxy150489 * Reads the firmware semaphore register and returns true (>0) if 109*5779Sxy150489 * manageability is enabled, else false (0). 110*5779Sxy150489 */ 111*5779Sxy150489 bool 112*5779Sxy150489 e1000_check_mng_mode_generic(struct e1000_hw *hw) 113*5779Sxy150489 { 114*5779Sxy150489 u32 fwsm; 115*5779Sxy150489 116*5779Sxy150489 DEBUGFUNC("e1000_check_mng_mode_generic"); 117*5779Sxy150489 118*5779Sxy150489 fwsm = E1000_READ_REG(hw, E1000_FWSM); 119*5779Sxy150489 120*5779Sxy150489 return ((fwsm & E1000_FWSM_MODE_MASK) == 121*5779Sxy150489 (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 122*5779Sxy150489 } 123*5779Sxy150489 124*5779Sxy150489 /* 125*5779Sxy150489 * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX 126*5779Sxy150489 * @hw: pointer to the HW structure 127*5779Sxy150489 * 128*5779Sxy150489 * Enables packet filtering on transmit packets if manageability is enabled 129*5779Sxy150489 * and host interface is enabled. 130*5779Sxy150489 */ 131*5779Sxy150489 bool 132*5779Sxy150489 e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) 133*5779Sxy150489 { 134*5779Sxy150489 struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; 135*5779Sxy150489 u32 *buffer = (u32 *)&hw->mng_cookie; 136*5779Sxy150489 u32 offset; 137*5779Sxy150489 s32 ret_val, hdr_csum, csum; 138*5779Sxy150489 u8 i, len; 139*5779Sxy150489 bool tx_filter = TRUE; 140*5779Sxy150489 141*5779Sxy150489 DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic"); 142*5779Sxy150489 143*5779Sxy150489 /* No manageability, no filtering */ 144*5779Sxy150489 if (!e1000_check_mng_mode(hw)) { 145*5779Sxy150489 tx_filter = FALSE; 146*5779Sxy150489 goto out; 147*5779Sxy150489 } 148*5779Sxy150489 149*5779Sxy150489 /* 150*5779Sxy150489 * If we can't read from the host interface for whatever 151*5779Sxy150489 * reason, disable filtering. 152*5779Sxy150489 */ 153*5779Sxy150489 ret_val = e1000_mng_enable_host_if(hw); 154*5779Sxy150489 if (ret_val != E1000_SUCCESS) { 155*5779Sxy150489 tx_filter = FALSE; 156*5779Sxy150489 goto out; 157*5779Sxy150489 } 158*5779Sxy150489 159*5779Sxy150489 /* Read in the header. Length and offset are in dwords. */ 160*5779Sxy150489 len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; 161*5779Sxy150489 offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; 162*5779Sxy150489 for (i = 0; i < len; i++) { 163*5779Sxy150489 *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, 164*5779Sxy150489 E1000_HOST_IF, offset + i); 165*5779Sxy150489 } 166*5779Sxy150489 hdr_csum = hdr->checksum; 167*5779Sxy150489 hdr->checksum = 0; 168*5779Sxy150489 csum = e1000_calculate_checksum((u8 *)hdr, 169*5779Sxy150489 E1000_MNG_DHCP_COOKIE_LENGTH); 170*5779Sxy150489 /* 171*5779Sxy150489 * If either the checksums or signature don't match, then 172*5779Sxy150489 * the cookie area isn't considered valid, in which case we 173*5779Sxy150489 * take the safe route of assuming Tx filtering is enabled. 174*5779Sxy150489 */ 175*5779Sxy150489 if (hdr_csum != csum) 176*5779Sxy150489 goto out; 177*5779Sxy150489 if (hdr->signature != E1000_IAMT_SIGNATURE) 178*5779Sxy150489 goto out; 179*5779Sxy150489 180*5779Sxy150489 /* Cookie area is valid, make the final check for filtering. */ 181*5779Sxy150489 if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) 182*5779Sxy150489 tx_filter = FALSE; 183*5779Sxy150489 184*5779Sxy150489 out: 185*5779Sxy150489 hw->mac.tx_pkt_filtering = tx_filter; 186*5779Sxy150489 return (tx_filter); 187*5779Sxy150489 } 188*5779Sxy150489 189*5779Sxy150489 /* 190*5779Sxy150489 * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface 191*5779Sxy150489 * @hw: pointer to the HW structure 192*5779Sxy150489 * @buffer: pointer to the host interface 193*5779Sxy150489 * @length: size of the buffer 194*5779Sxy150489 * 195*5779Sxy150489 * Writes the DHCP information to the host interface. 196*5779Sxy150489 */ 197*5779Sxy150489 s32 198*5779Sxy150489 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer, 199*5779Sxy150489 u16 length) 200*5779Sxy150489 { 201*5779Sxy150489 struct e1000_host_mng_command_header hdr; 202*5779Sxy150489 s32 ret_val; 203*5779Sxy150489 u32 hicr; 204*5779Sxy150489 205*5779Sxy150489 DEBUGFUNC("e1000_mng_write_dhcp_info_generic"); 206*5779Sxy150489 207*5779Sxy150489 hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; 208*5779Sxy150489 hdr.command_length = length; 209*5779Sxy150489 hdr.reserved1 = 0; 210*5779Sxy150489 hdr.reserved2 = 0; 211*5779Sxy150489 hdr.checksum = 0; 212*5779Sxy150489 213*5779Sxy150489 /* Enable the host interface */ 214*5779Sxy150489 ret_val = e1000_mng_enable_host_if(hw); 215*5779Sxy150489 if (ret_val) 216*5779Sxy150489 goto out; 217*5779Sxy150489 218*5779Sxy150489 /* Populate the host interface with the contents of "buffer". */ 219*5779Sxy150489 ret_val = e1000_mng_host_if_write(hw, buffer, length, 220*5779Sxy150489 sizeof (hdr), &(hdr.checksum)); 221*5779Sxy150489 if (ret_val) 222*5779Sxy150489 goto out; 223*5779Sxy150489 224*5779Sxy150489 /* Write the manageability command header */ 225*5779Sxy150489 ret_val = e1000_mng_write_cmd_header(hw, &hdr); 226*5779Sxy150489 if (ret_val) 227*5779Sxy150489 goto out; 228*5779Sxy150489 229*5779Sxy150489 /* Tell the ARC a new command is pending. */ 230*5779Sxy150489 hicr = E1000_READ_REG(hw, E1000_HICR); 231*5779Sxy150489 E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C); 232*5779Sxy150489 233*5779Sxy150489 out: 234*5779Sxy150489 return (ret_val); 235*5779Sxy150489 } 236*5779Sxy150489 237*5779Sxy150489 /* 238*5779Sxy150489 * e1000_mng_write_cmd_header_generic - Writes manageability command header 239*5779Sxy150489 * @hw: pointer to the HW structure 240*5779Sxy150489 * @hdr: pointer to the host interface command header 241*5779Sxy150489 * 242*5779Sxy150489 * Writes the command header after does the checksum calculation. 243*5779Sxy150489 */ 244*5779Sxy150489 s32 245*5779Sxy150489 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw, 246*5779Sxy150489 struct e1000_host_mng_command_header *hdr) 247*5779Sxy150489 { 248*5779Sxy150489 u16 i, length = sizeof (struct e1000_host_mng_command_header); 249*5779Sxy150489 250*5779Sxy150489 DEBUGFUNC("e1000_mng_write_cmd_header_generic"); 251*5779Sxy150489 252*5779Sxy150489 /* Write the whole command header structure with new checksum. */ 253*5779Sxy150489 254*5779Sxy150489 hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); 255*5779Sxy150489 256*5779Sxy150489 length >>= 2; 257*5779Sxy150489 /* Write the relevant command block into the ram area. */ 258*5779Sxy150489 for (i = 0; i < length; i++) { 259*5779Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i, 260*5779Sxy150489 *((u32 *)(uintptr_t)hdr + i)); 261*5779Sxy150489 E1000_WRITE_FLUSH(hw); 262*5779Sxy150489 } 263*5779Sxy150489 264*5779Sxy150489 return (E1000_SUCCESS); 265*5779Sxy150489 } 266*5779Sxy150489 267*5779Sxy150489 /* 268*5779Sxy150489 * e1000_mng_host_if_write_generic - Write to the manageability host interface 269*5779Sxy150489 * @hw: pointer to the HW structure 270*5779Sxy150489 * @buffer: pointer to the host interface buffer 271*5779Sxy150489 * @length: size of the buffer 272*5779Sxy150489 * @offset: location in the buffer to write to 273*5779Sxy150489 * @sum: sum of the data (not checksum) 274*5779Sxy150489 * 275*5779Sxy150489 * This function writes the buffer content at the offset given on the host if. 276*5779Sxy150489 * It also does alignment considerations to do the writes in most efficient 277*5779Sxy150489 * way. Also fills up the sum of the buffer in *buffer parameter. 278*5779Sxy150489 */ 279*5779Sxy150489 s32 280*5779Sxy150489 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, 281*5779Sxy150489 u16 length, u16 offset, u8 *sum) 282*5779Sxy150489 { 283*5779Sxy150489 u8 *tmp; 284*5779Sxy150489 u8 *bufptr = buffer; 285*5779Sxy150489 u32 data = 0; 286*5779Sxy150489 s32 ret_val = E1000_SUCCESS; 287*5779Sxy150489 u16 remaining, i, j, prev_bytes; 288*5779Sxy150489 289*5779Sxy150489 DEBUGFUNC("e1000_mng_host_if_write_generic"); 290*5779Sxy150489 291*5779Sxy150489 /* sum = only sum of the data and it is not checksum */ 292*5779Sxy150489 293*5779Sxy150489 if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { 294*5779Sxy150489 ret_val = -E1000_ERR_PARAM; 295*5779Sxy150489 goto out; 296*5779Sxy150489 } 297*5779Sxy150489 298*5779Sxy150489 tmp = (u8 *)&data; 299*5779Sxy150489 prev_bytes = offset & 0x3; 300*5779Sxy150489 offset >>= 2; 301*5779Sxy150489 302*5779Sxy150489 if (prev_bytes) { 303*5779Sxy150489 data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset); 304*5779Sxy150489 for (j = prev_bytes; j < sizeof (u32); j++) { 305*5779Sxy150489 *(tmp + j) = *bufptr++; 306*5779Sxy150489 *sum += *(tmp + j); 307*5779Sxy150489 } 308*5779Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data); 309*5779Sxy150489 length -= j - prev_bytes; 310*5779Sxy150489 offset++; 311*5779Sxy150489 } 312*5779Sxy150489 313*5779Sxy150489 remaining = length & 0x3; 314*5779Sxy150489 length -= remaining; 315*5779Sxy150489 316*5779Sxy150489 /* Calculate length in DWORDs */ 317*5779Sxy150489 length >>= 2; 318*5779Sxy150489 319*5779Sxy150489 /* 320*5779Sxy150489 * The device driver writes the relevant command block into the 321*5779Sxy150489 * ram area. 322*5779Sxy150489 */ 323*5779Sxy150489 for (i = 0; i < length; i++) { 324*5779Sxy150489 for (j = 0; j < sizeof (u32); j++) { 325*5779Sxy150489 *(tmp + j) = *bufptr++; 326*5779Sxy150489 *sum += *(tmp + j); 327*5779Sxy150489 } 328*5779Sxy150489 329*5779Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, 330*5779Sxy150489 offset + i, data); 331*5779Sxy150489 } 332*5779Sxy150489 if (remaining) { 333*5779Sxy150489 for (j = 0; j < sizeof (u32); j++) { 334*5779Sxy150489 if (j < remaining) 335*5779Sxy150489 *(tmp + j) = *bufptr++; 336*5779Sxy150489 else 337*5779Sxy150489 *(tmp + j) = 0; 338*5779Sxy150489 339*5779Sxy150489 *sum += *(tmp + j); 340*5779Sxy150489 } 341*5779Sxy150489 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, 342*5779Sxy150489 offset + i, data); 343*5779Sxy150489 } 344*5779Sxy150489 345*5779Sxy150489 out: 346*5779Sxy150489 return (ret_val); 347*5779Sxy150489 } 348*5779Sxy150489 349*5779Sxy150489 /* 350*5779Sxy150489 * e1000_enable_mng_pass_thru - Enable processing of ARP's 351*5779Sxy150489 * @hw: pointer to the HW structure 352*5779Sxy150489 * 353*5779Sxy150489 * Verifies the hardware needs to allow ARPs to be processed by the host. 354*5779Sxy150489 */ 355*5779Sxy150489 bool 356*5779Sxy150489 e1000_enable_mng_pass_thru(struct e1000_hw *hw) 357*5779Sxy150489 { 358*5779Sxy150489 u32 manc; 359*5779Sxy150489 u32 fwsm, factps; 360*5779Sxy150489 bool ret_val = FALSE; 361*5779Sxy150489 362*5779Sxy150489 DEBUGFUNC("e1000_enable_mng_pass_thru"); 363*5779Sxy150489 364*5779Sxy150489 if (!hw->mac.asf_firmware_present) 365*5779Sxy150489 goto out; 366*5779Sxy150489 367*5779Sxy150489 manc = E1000_READ_REG(hw, E1000_MANC); 368*5779Sxy150489 369*5779Sxy150489 if (!(manc & E1000_MANC_RCV_TCO_EN) || 370*5779Sxy150489 !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) 371*5779Sxy150489 goto out; 372*5779Sxy150489 373*5779Sxy150489 if (hw->mac.arc_subsystem_valid) { 374*5779Sxy150489 fwsm = E1000_READ_REG(hw, E1000_FWSM); 375*5779Sxy150489 factps = E1000_READ_REG(hw, E1000_FACTPS); 376*5779Sxy150489 377*5779Sxy150489 if (!(factps & E1000_FACTPS_MNGCG) && 378*5779Sxy150489 ((fwsm & E1000_FWSM_MODE_MASK) == 379*5779Sxy150489 (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { 380*5779Sxy150489 ret_val = TRUE; 381*5779Sxy150489 goto out; 382*5779Sxy150489 } 383*5779Sxy150489 } else { 384*5779Sxy150489 if ((manc & E1000_MANC_SMBUS_EN) && 385*5779Sxy150489 !(manc & E1000_MANC_ASF_EN)) { 386*5779Sxy150489 ret_val = TRUE; 387*5779Sxy150489 goto out; 388*5779Sxy150489 } 389*5779Sxy150489 } 390*5779Sxy150489 391*5779Sxy150489 out: 392*5779Sxy150489 return (ret_val); 393*5779Sxy150489 } 394