1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2015-2020 Beijing WangXun Technology Co., Ltd. 3 * Copyright(c) 2010-2017 Intel Corporation 4 */ 5 6 #include "txgbe_type.h" 7 #include "txgbe_mng.h" 8 9 /** 10 * txgbe_calculate_checksum - Calculate checksum for buffer 11 * @buffer: pointer to EEPROM 12 * @length: size of EEPROM to calculate a checksum for 13 * Calculates the checksum for some buffer on a specified length. The 14 * checksum calculated is returned. 15 **/ 16 static u8 17 txgbe_calculate_checksum(u8 *buffer, u32 length) 18 { 19 u32 i; 20 u8 sum = 0; 21 22 for (i = 0; i < length; i++) 23 sum += buffer[i]; 24 25 return (u8)(0 - sum); 26 } 27 28 /** 29 * txgbe_hic_unlocked - Issue command to manageability block unlocked 30 * @hw: pointer to the HW structure 31 * @buffer: command to write and where the return status will be placed 32 * @length: length of buffer, must be multiple of 4 bytes 33 * @timeout: time in ms to wait for command completion 34 * 35 * Communicates with the manageability block. On success return 0 36 * else returns semaphore error when encountering an error acquiring 37 * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. 38 * 39 * This function assumes that the TXGBE_MNGSEM_SWMBX semaphore is held 40 * by the caller. 41 **/ 42 static s32 43 txgbe_hic_unlocked(struct txgbe_hw *hw, u32 *buffer, u32 length, u32 timeout) 44 { 45 u32 value, loop; 46 u16 i, dword_len; 47 48 if (!length || length > TXGBE_PMMBX_BSIZE) { 49 DEBUGOUT("Buffer length failure buffersize=%d.", length); 50 return TXGBE_ERR_HOST_INTERFACE_COMMAND; 51 } 52 53 /* Calculate length in DWORDs. We must be DWORD aligned */ 54 if (length % sizeof(u32)) { 55 DEBUGOUT("Buffer length failure, not aligned to dword"); 56 return TXGBE_ERR_INVALID_ARGUMENT; 57 } 58 59 dword_len = length >> 2; 60 61 txgbe_flush(hw); 62 /* The device driver writes the relevant command block 63 * into the ram area. 64 */ 65 for (i = 0; i < dword_len; i++) { 66 wr32a(hw, TXGBE_MNGMBX, i, cpu_to_le32(buffer[i])); 67 buffer[i] = rd32a(hw, TXGBE_MNGMBX, i); 68 } 69 txgbe_flush(hw); 70 71 /* Setting this bit tells the ARC that a new command is pending. */ 72 wr32m(hw, TXGBE_MNGMBXCTL, 73 TXGBE_MNGMBXCTL_SWRDY, TXGBE_MNGMBXCTL_SWRDY); 74 75 /* Check command completion */ 76 loop = po32m(hw, TXGBE_MNGMBXCTL, 77 TXGBE_MNGMBXCTL_FWRDY, TXGBE_MNGMBXCTL_FWRDY, 78 &value, timeout, 1000); 79 if (!loop || !(value & TXGBE_MNGMBXCTL_FWACK)) { 80 DEBUGOUT("Command has failed with no status valid."); 81 return TXGBE_ERR_HOST_INTERFACE_COMMAND; 82 } 83 84 if ((rd32(hw, TXGBE_MNGMBX) & 0xff0000) >> 16 == 0x80) { 85 DEBUGOUT("It's unknown command."); 86 return TXGBE_ERR_MNG_ACCESS_FAILED; 87 } 88 89 return 0; 90 } 91 92 /** 93 * txgbe_host_interface_command - Issue command to manageability block 94 * @hw: pointer to the HW structure 95 * @buffer: contains the command to write and where the return status will 96 * be placed 97 * @length: length of buffer, must be multiple of 4 bytes 98 * @timeout: time in ms to wait for command completion 99 * @return_data: read and return data from the buffer (true) or not (false) 100 * Needed because FW structures are big endian and decoding of 101 * these fields can be 8 bit or 16 bit based on command. Decoding 102 * is not easily understood without making a table of commands. 103 * So we will leave this up to the caller to read back the data 104 * in these cases. 105 * 106 * Communicates with the manageability block. On success return 0 107 * else returns semaphore error when encountering an error acquiring 108 * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. 109 **/ 110 static s32 111 txgbe_host_interface_command(struct txgbe_hw *hw, u32 *buffer, 112 u32 length, u32 timeout, bool return_data) 113 { 114 u32 hdr_size = sizeof(struct txgbe_hic_hdr); 115 struct txgbe_hic_hdr *resp = (struct txgbe_hic_hdr *)buffer; 116 u16 buf_len; 117 s32 err; 118 u32 bi; 119 u32 dword_len; 120 121 if (length == 0 || length > TXGBE_PMMBX_BSIZE) { 122 DEBUGOUT("Buffer length failure buffersize=%d.", length); 123 return TXGBE_ERR_HOST_INTERFACE_COMMAND; 124 } 125 126 /* Take management host interface semaphore */ 127 err = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWMBX); 128 if (err) 129 return err; 130 131 err = txgbe_hic_unlocked(hw, buffer, length, timeout); 132 if (err) 133 goto rel_out; 134 135 if (!return_data) 136 goto rel_out; 137 138 /* Calculate length in DWORDs */ 139 dword_len = hdr_size >> 2; 140 141 /* first pull in the header so we know the buffer length */ 142 for (bi = 0; bi < dword_len; bi++) 143 buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi); 144 145 buf_len = resp->buf_len; 146 if (!buf_len) 147 goto rel_out; 148 149 if (length < buf_len + hdr_size) { 150 DEBUGOUT("Buffer not large enough for reply message."); 151 err = TXGBE_ERR_HOST_INTERFACE_COMMAND; 152 goto rel_out; 153 } 154 155 /* Calculate length in DWORDs, add 3 for odd lengths */ 156 dword_len = (buf_len + 3) >> 2; 157 158 /* Pull in the rest of the buffer (bi is where we left off) */ 159 for (; bi <= dword_len; bi++) 160 buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi); 161 162 rel_out: 163 hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWMBX); 164 165 return err; 166 } 167 168 /** 169 * txgbe_hic_sr_read - Read EEPROM word using a host interface cmd 170 * assuming that the semaphore is already obtained. 171 * @hw: pointer to hardware structure 172 * @offset: offset of word in the EEPROM to read 173 * @data: word read from the EEPROM 174 * 175 * Reads a 16 bit word from the EEPROM using the hostif. 176 **/ 177 s32 txgbe_hic_sr_read(struct txgbe_hw *hw, u32 addr, u8 *buf, int len) 178 { 179 struct txgbe_hic_read_shadow_ram command; 180 u32 value; 181 int err, i = 0, j = 0; 182 183 if (len > TXGBE_PMMBX_DATA_SIZE) 184 return TXGBE_ERR_HOST_INTERFACE_COMMAND; 185 186 memset(&command, 0, sizeof(command)); 187 command.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD; 188 command.hdr.req.buf_lenh = 0; 189 command.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN; 190 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 191 command.address = cpu_to_be32(addr); 192 command.length = cpu_to_be16(len); 193 194 err = txgbe_hic_unlocked(hw, (u32 *)&command, 195 sizeof(command), TXGBE_HI_COMMAND_TIMEOUT); 196 if (err) 197 return err; 198 199 while (i < (len >> 2)) { 200 value = rd32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i); 201 ((u32 *)buf)[i] = value; 202 i++; 203 } 204 205 value = rd32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i); 206 for (i <<= 2; i < len; i++) 207 ((u8 *)buf)[i] = ((u8 *)&value)[j++]; 208 209 return 0; 210 } 211 212 /** 213 * txgbe_hic_sr_write - Write EEPROM word using hostif 214 * @hw: pointer to hardware structure 215 * @offset: offset of word in the EEPROM to write 216 * @data: word write to the EEPROM 217 * 218 * Write a 16 bit word to the EEPROM using the hostif. 219 **/ 220 s32 txgbe_hic_sr_write(struct txgbe_hw *hw, u32 addr, u8 *buf, int len) 221 { 222 struct txgbe_hic_write_shadow_ram command; 223 u32 value; 224 int err = 0, i = 0, j = 0; 225 226 if (len > TXGBE_PMMBX_DATA_SIZE) 227 return TXGBE_ERR_HOST_INTERFACE_COMMAND; 228 229 memset(&command, 0, sizeof(command)); 230 command.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD; 231 command.hdr.req.buf_lenh = 0; 232 command.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN; 233 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 234 command.address = cpu_to_be32(addr); 235 command.length = cpu_to_be16(len); 236 237 while (i < (len >> 2)) { 238 value = ((u32 *)buf)[i]; 239 wr32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i, value); 240 i++; 241 } 242 243 for (i <<= 2; i < len; i++) 244 ((u8 *)&value)[j++] = ((u8 *)buf)[i]; 245 246 wr32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + (i >> 2), value); 247 248 UNREFERENCED_PARAMETER(&command); 249 250 return err; 251 } 252 253 s32 txgbe_close_notify(struct txgbe_hw *hw) 254 { 255 u32 tmp; 256 s32 status; 257 struct txgbe_hic_write_shadow_ram buffer; 258 259 buffer.hdr.req.cmd = FW_DW_CLOSE_NOTIFY; 260 buffer.hdr.req.buf_lenh = 0; 261 buffer.hdr.req.buf_lenl = 0; 262 buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 263 264 /* one word */ 265 buffer.length = 0; 266 buffer.address = 0; 267 268 status = txgbe_host_interface_command(hw, (u32 *)&buffer, 269 sizeof(buffer), 270 TXGBE_HI_COMMAND_TIMEOUT, false); 271 if (status) 272 return status; 273 274 tmp = rd32a(hw, TXGBE_MNGMBX, 1); 275 if (tmp == TXGBE_CHECKSUM_CAP_ST_PASS) 276 status = 0; 277 else 278 status = TXGBE_ERR_EEPROM_CHECKSUM; 279 280 return status; 281 } 282 283 s32 txgbe_open_notify(struct txgbe_hw *hw) 284 { 285 u32 tmp; 286 s32 status; 287 struct txgbe_hic_write_shadow_ram buffer; 288 289 buffer.hdr.req.cmd = FW_DW_OPEN_NOTIFY; 290 buffer.hdr.req.buf_lenh = 0; 291 buffer.hdr.req.buf_lenl = 0; 292 buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 293 294 /* one word */ 295 buffer.length = 0; 296 buffer.address = 0; 297 298 status = txgbe_host_interface_command(hw, (u32 *)&buffer, 299 sizeof(buffer), 300 TXGBE_HI_COMMAND_TIMEOUT, false); 301 if (status) 302 return status; 303 304 tmp = rd32a(hw, TXGBE_MNGMBX, 1); 305 if (tmp == TXGBE_CHECKSUM_CAP_ST_PASS) 306 status = 0; 307 else 308 status = TXGBE_ERR_EEPROM_CHECKSUM; 309 310 return status; 311 } 312 313 /** 314 * txgbe_hic_set_drv_ver - Sends driver version to firmware 315 * @hw: pointer to the HW structure 316 * @maj: driver version major number 317 * @min: driver version minor number 318 * @build: driver version build number 319 * @sub: driver version sub build number 320 * @len: unused 321 * @driver_ver: unused 322 * 323 * Sends driver version number to firmware through the manageability 324 * block. On success return 0 325 * else returns TXGBE_ERR_SWFW_SYNC when encountering an error acquiring 326 * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. 327 **/ 328 s32 txgbe_hic_set_drv_ver(struct txgbe_hw *hw, u8 maj, u8 min, 329 u8 build, u8 sub, u16 len, 330 const char *driver_ver) 331 { 332 struct txgbe_hic_drv_info fw_cmd; 333 int i; 334 s32 ret_val = 0; 335 336 UNREFERENCED_PARAMETER(len, driver_ver); 337 338 fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; 339 fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN; 340 fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; 341 fw_cmd.port_num = (u8)hw->bus.func; 342 fw_cmd.ver_maj = maj; 343 fw_cmd.ver_min = min; 344 fw_cmd.ver_build = build; 345 fw_cmd.ver_sub = sub; 346 fw_cmd.hdr.checksum = 0; 347 fw_cmd.pad = 0; 348 fw_cmd.pad2 = 0; 349 fw_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&fw_cmd, 350 (FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len)); 351 352 for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { 353 ret_val = txgbe_host_interface_command(hw, (u32 *)&fw_cmd, 354 sizeof(fw_cmd), 355 TXGBE_HI_COMMAND_TIMEOUT, 356 true); 357 if (ret_val != 0) 358 continue; 359 360 if (fw_cmd.hdr.cmd_or_resp.ret_status == 361 FW_CEM_RESP_STATUS_SUCCESS) 362 ret_val = 0; 363 else 364 ret_val = TXGBE_ERR_HOST_INTERFACE_COMMAND; 365 366 break; 367 } 368 369 return ret_val; 370 } 371 372 /** 373 * txgbe_hic_reset - send reset cmd to fw 374 * @hw: pointer to hardware structure 375 * 376 * Sends reset cmd to firmware through the manageability 377 * block. On success return 0 378 * else returns TXGBE_ERR_SWFW_SYNC when encountering an error acquiring 379 * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. 380 **/ 381 s32 382 txgbe_hic_reset(struct txgbe_hw *hw) 383 { 384 struct txgbe_hic_reset reset_cmd; 385 int i; 386 s32 err = 0; 387 388 reset_cmd.hdr.cmd = FW_RESET_CMD; 389 reset_cmd.hdr.buf_len = FW_RESET_LEN; 390 reset_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; 391 reset_cmd.lan_id = hw->bus.lan_id; 392 reset_cmd.reset_type = (u16)hw->reset_type; 393 reset_cmd.hdr.checksum = 0; 394 reset_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&reset_cmd, 395 (FW_CEM_HDR_LEN + reset_cmd.hdr.buf_len)); 396 397 for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { 398 err = txgbe_host_interface_command(hw, (u32 *)&reset_cmd, 399 sizeof(reset_cmd), 400 TXGBE_HI_COMMAND_TIMEOUT, 401 true); 402 if (err != 0) 403 continue; 404 405 if (reset_cmd.hdr.cmd_or_resp.ret_status == 406 FW_CEM_RESP_STATUS_SUCCESS) 407 err = 0; 408 else 409 err = TXGBE_ERR_HOST_INTERFACE_COMMAND; 410 411 break; 412 } 413 414 return err; 415 } 416 417 /** 418 * txgbe_mng_present - returns true when management capability is present 419 * @hw: pointer to hardware structure 420 */ 421 bool 422 txgbe_mng_present(struct txgbe_hw *hw) 423 { 424 if (hw->mac.type == txgbe_mac_unknown) 425 return false; 426 427 return !!rd32m(hw, TXGBE_STAT, TXGBE_STAT_MNGINIT); 428 } 429 430 /** 431 * txgbe_mng_enabled - Is the manageability engine enabled? 432 * @hw: pointer to hardware structure 433 * 434 * Returns true if the manageability engine is enabled. 435 **/ 436 bool 437 txgbe_mng_enabled(struct txgbe_hw *hw) 438 { 439 UNREFERENCED_PARAMETER(hw); 440 /* firmware does not control laser */ 441 return false; 442 } 443 444 s32 txgbe_hic_get_lldp(struct txgbe_hw *hw) 445 { 446 struct txgbe_hic_write_lldp buffer; 447 s32 err = 0; 448 449 buffer.hdr.cmd = FW_LLDP_GET_CMD; 450 buffer.hdr.buf_len = 0x1; 451 buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; 452 buffer.hdr.checksum = FW_DEFAULT_CHECKSUM; 453 buffer.func = hw->bus.lan_id; 454 455 err = txgbe_host_interface_command(hw, (u32 *)&buffer, sizeof(buffer), 456 TXGBE_HI_COMMAND_TIMEOUT, true); 457 if (err) 458 return err; 459 460 if (buffer.hdr.cmd_or_resp.ret_status == FW_CEM_RESP_STATUS_SUCCESS) { 461 /* this field returns the status of LLDP */ 462 if (buffer.func) 463 hw->lldp_enabled = true; 464 else 465 hw->lldp_enabled = false; 466 } else { 467 err = TXGBE_ERR_HOST_INTERFACE_COMMAND; 468 } 469 470 return err; 471 } 472 473 s32 txgbe_hic_set_lldp(struct txgbe_hw *hw, bool on) 474 { 475 struct txgbe_hic_write_lldp buffer; 476 477 if (on) 478 buffer.hdr.cmd = FW_LLDP_SET_CMD_ON; 479 else 480 buffer.hdr.cmd = FW_LLDP_SET_CMD_OFF; 481 buffer.hdr.buf_len = 0x1; 482 buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; 483 buffer.hdr.checksum = FW_DEFAULT_CHECKSUM; 484 buffer.func = hw->bus.lan_id; 485 486 return txgbe_host_interface_command(hw, (u32 *)&buffer, sizeof(buffer), 487 TXGBE_HI_COMMAND_TIMEOUT, false); 488 } 489