1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd. 3 * Copyright(c) 2010-2017 Intel Corporation 4 */ 5 6 #include "ngbe_type.h" 7 #include "ngbe_mng.h" 8 9 /** 10 * ngbe_hic_unlocked - Issue command to manageability block unlocked 11 * @hw: pointer to the HW structure 12 * @buffer: command to write and where the return status will be placed 13 * @length: length of buffer, must be multiple of 4 bytes 14 * @timeout: time in ms to wait for command completion 15 * 16 * Communicates with the manageability block. On success return 0 17 * else returns semaphore error when encountering an error acquiring 18 * semaphore or NGBE_ERR_HOST_INTERFACE_COMMAND when command fails. 19 * 20 * This function assumes that the NGBE_MNGSEM_SWMBX semaphore is held 21 * by the caller. 22 **/ 23 static s32 24 ngbe_hic_unlocked(struct ngbe_hw *hw, u32 *buffer, u32 length, u32 timeout) 25 { 26 u32 value, loop; 27 u16 i, dword_len; 28 29 if (!length || length > NGBE_PMMBX_BSIZE) { 30 DEBUGOUT("Buffer length failure buffersize=%d.", length); 31 return NGBE_ERR_HOST_INTERFACE_COMMAND; 32 } 33 34 /* Calculate length in DWORDs. We must be DWORD aligned */ 35 if (length % sizeof(u32)) { 36 DEBUGOUT("Buffer length failure, not aligned to dword"); 37 return NGBE_ERR_INVALID_ARGUMENT; 38 } 39 40 dword_len = length >> 2; 41 42 /* The device driver writes the relevant command block 43 * into the ram area. 44 */ 45 for (i = 0; i < dword_len; i++) { 46 wr32a(hw, NGBE_MNGMBX, i, cpu_to_le32(buffer[i])); 47 buffer[i] = rd32a(hw, NGBE_MNGMBX, i); 48 } 49 ngbe_flush(hw); 50 51 /* Setting this bit tells the ARC that a new command is pending. */ 52 wr32m(hw, NGBE_MNGMBXCTL, 53 NGBE_MNGMBXCTL_SWRDY, NGBE_MNGMBXCTL_SWRDY); 54 55 /* Check command completion */ 56 loop = po32m(hw, NGBE_MNGMBXCTL, 57 NGBE_MNGMBXCTL_FWRDY, NGBE_MNGMBXCTL_FWRDY, 58 &value, timeout, 1000); 59 if (!loop || !(value & NGBE_MNGMBXCTL_FWACK)) { 60 DEBUGOUT("Command has failed with no status valid."); 61 return NGBE_ERR_HOST_INTERFACE_COMMAND; 62 } 63 64 return 0; 65 } 66 67 /** 68 * ngbe_host_interface_command - Issue command to manageability block 69 * @hw: pointer to the HW structure 70 * @buffer: contains the command to write and where the return status will 71 * be placed 72 * @length: length of buffer, must be multiple of 4 bytes 73 * @timeout: time in ms to wait for command completion 74 * @return_data: read and return data from the buffer (true) or not (false) 75 * Needed because FW structures are big endian and decoding of 76 * these fields can be 8 bit or 16 bit based on command. Decoding 77 * is not easily understood without making a table of commands. 78 * So we will leave this up to the caller to read back the data 79 * in these cases. 80 * 81 * Communicates with the manageability block. On success return 0 82 * else returns semaphore error when encountering an error acquiring 83 * semaphore or NGBE_ERR_HOST_INTERFACE_COMMAND when command fails. 84 **/ 85 static s32 86 ngbe_host_interface_command(struct ngbe_hw *hw, u32 *buffer, 87 u32 length, u32 timeout, bool return_data) 88 { 89 u32 hdr_size = sizeof(struct ngbe_hic_hdr); 90 struct ngbe_hic_hdr *resp = (struct ngbe_hic_hdr *)buffer; 91 u16 buf_len; 92 s32 err; 93 u32 bi; 94 u32 dword_len; 95 96 if (length == 0 || length > NGBE_PMMBX_BSIZE) { 97 DEBUGOUT("Buffer length failure buffersize=%d.", length); 98 return NGBE_ERR_HOST_INTERFACE_COMMAND; 99 } 100 101 /* Take management host interface semaphore */ 102 err = hw->mac.acquire_swfw_sync(hw, NGBE_MNGSEM_SWMBX); 103 if (err) 104 return err; 105 106 err = ngbe_hic_unlocked(hw, buffer, length, timeout); 107 if (err) 108 goto rel_out; 109 110 if (!return_data) 111 goto rel_out; 112 113 /* Calculate length in DWORDs */ 114 dword_len = hdr_size >> 2; 115 116 /* first pull in the header so we know the buffer length */ 117 for (bi = 0; bi < dword_len; bi++) 118 buffer[bi] = rd32a(hw, NGBE_MNGMBX, bi); 119 120 buf_len = resp->buf_len; 121 if (!buf_len) 122 goto rel_out; 123 124 if (length < buf_len + hdr_size) { 125 DEBUGOUT("Buffer not large enough for reply message."); 126 err = NGBE_ERR_HOST_INTERFACE_COMMAND; 127 goto rel_out; 128 } 129 130 /* Calculate length in DWORDs, add 3 for odd lengths */ 131 dword_len = (buf_len + 3) >> 2; 132 133 /* Pull in the rest of the buffer (bi is where we left off) */ 134 for (; bi <= dword_len; bi++) 135 buffer[bi] = rd32a(hw, NGBE_MNGMBX, bi); 136 137 rel_out: 138 hw->mac.release_swfw_sync(hw, NGBE_MNGSEM_SWMBX); 139 140 return err; 141 } 142 143 /** 144 * ngbe_hic_sr_read - Read EEPROM word using a host interface cmd 145 * assuming that the semaphore is already obtained. 146 * @hw: pointer to hardware structure 147 * @offset: offset of word in the EEPROM to read 148 * @data: word read from the EEPROM 149 * 150 * Reads a 16 bit word from the EEPROM using the hostif. 151 **/ 152 s32 ngbe_hic_sr_read(struct ngbe_hw *hw, u32 addr, u8 *buf, int len) 153 { 154 struct ngbe_hic_read_shadow_ram command; 155 u32 value; 156 int err, i = 0, j = 0; 157 158 if (len > NGBE_PMMBX_DATA_SIZE) 159 return NGBE_ERR_HOST_INTERFACE_COMMAND; 160 161 memset(&command, 0, sizeof(command)); 162 command.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD; 163 command.hdr.req.buf_lenh = 0; 164 command.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN; 165 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 166 command.address = cpu_to_be32(addr); 167 command.length = cpu_to_be16(len); 168 169 err = ngbe_hic_unlocked(hw, (u32 *)&command, 170 sizeof(command), NGBE_HI_COMMAND_TIMEOUT); 171 if (err) 172 return err; 173 174 while (i < (len >> 2)) { 175 value = rd32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + i); 176 ((u32 *)buf)[i] = value; 177 i++; 178 } 179 180 value = rd32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + i); 181 for (i <<= 2; i < len; i++) 182 ((u8 *)buf)[i] = ((u8 *)&value)[j++]; 183 184 return 0; 185 } 186 187 /** 188 * ngbe_hic_sr_write - Write EEPROM word using hostif 189 * @hw: pointer to hardware structure 190 * @offset: offset of word in the EEPROM to write 191 * @data: word write to the EEPROM 192 * 193 * Write a 16 bit word to the EEPROM using the hostif. 194 **/ 195 s32 ngbe_hic_sr_write(struct ngbe_hw *hw, u32 addr, u8 *buf, int len) 196 { 197 struct ngbe_hic_write_shadow_ram command; 198 u32 value; 199 int err = 0, i = 0, j = 0; 200 201 if (len > NGBE_PMMBX_DATA_SIZE) 202 return NGBE_ERR_HOST_INTERFACE_COMMAND; 203 204 memset(&command, 0, sizeof(command)); 205 command.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD; 206 command.hdr.req.buf_lenh = 0; 207 command.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN; 208 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 209 command.address = cpu_to_be32(addr); 210 command.length = cpu_to_be16(len); 211 212 while (i < (len >> 2)) { 213 value = ((u32 *)buf)[i]; 214 wr32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + i, value); 215 i++; 216 } 217 218 for (i <<= 2; i < len; i++) 219 ((u8 *)&value)[j++] = ((u8 *)buf)[i]; 220 221 wr32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + (i >> 2), value); 222 223 UNREFERENCED_PARAMETER(&command); 224 225 return err; 226 } 227 228 s32 ngbe_hic_pcie_read(struct ngbe_hw *hw, u16 addr, u32 *buf, int len) 229 { 230 struct ngbe_hic_read_pcie command; 231 u32 value = 0; 232 int err, i = 0; 233 234 if (len > NGBE_PMMBX_DATA_SIZE) 235 return NGBE_ERR_HOST_INTERFACE_COMMAND; 236 237 memset(&command, 0, sizeof(command)); 238 command.hdr.cmd = FW_PCIE_READ_CMD; 239 command.hdr.buf_len = sizeof(command) - sizeof(command.hdr); 240 command.hdr.checksum = FW_DEFAULT_CHECKSUM; 241 command.lan_id = hw->bus.lan_id; 242 command.addr = addr; 243 244 err = ngbe_host_interface_command(hw, (u32 *)&command, 245 sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false); 246 if (err) 247 return err; 248 249 while (i < (len >> 2)) { 250 value = rd32a(hw, NGBE_MNGMBX, FW_PCIE_BUSMASTER_OFFSET + i); 251 ((u32 *)buf)[i] = value; 252 i++; 253 } 254 255 return 0; 256 } 257 258 s32 ngbe_hic_pcie_write(struct ngbe_hw *hw, u16 addr, u32 *buf, int len) 259 { 260 struct ngbe_hic_write_pcie command; 261 u32 value = 0; 262 int err, i = 0; 263 264 while (i < (len >> 2)) { 265 value = ((u32 *)buf)[i]; 266 i++; 267 } 268 269 memset(&command, 0, sizeof(command)); 270 command.hdr.cmd = FW_PCIE_WRITE_CMD; 271 command.hdr.buf_len = sizeof(command) - sizeof(command.hdr); 272 command.hdr.checksum = FW_DEFAULT_CHECKSUM; 273 command.lan_id = hw->bus.lan_id; 274 command.addr = addr; 275 command.data = value; 276 277 err = ngbe_host_interface_command(hw, (u32 *)&command, 278 sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false); 279 if (err) 280 return err; 281 282 return 0; 283 } 284 285 s32 ngbe_hic_check_cap(struct ngbe_hw *hw) 286 { 287 struct ngbe_hic_read_shadow_ram command; 288 s32 err; 289 int i; 290 291 command.hdr.req.cmd = FW_EEPROM_CHECK_STATUS; 292 command.hdr.req.buf_lenh = 0; 293 command.hdr.req.buf_lenl = 0; 294 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 295 296 /* convert offset from words to bytes */ 297 command.address = 0; 298 /* one word */ 299 command.length = 0; 300 301 for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { 302 err = ngbe_host_interface_command(hw, (u32 *)&command, 303 sizeof(command), 304 NGBE_HI_COMMAND_TIMEOUT, true); 305 if (err) 306 continue; 307 308 command.hdr.rsp.ret_status &= 0x1F; 309 if (command.hdr.rsp.ret_status != 310 FW_CEM_RESP_STATUS_SUCCESS) 311 err = NGBE_ERR_HOST_INTERFACE_COMMAND; 312 313 break; 314 } 315 316 if (!err && command.address != FW_CHECKSUM_CAP_ST_PASS) 317 err = NGBE_ERR_EEPROM_CHECKSUM; 318 319 return err; 320 } 321 322 s32 ngbe_phy_led_oem_chk(struct ngbe_hw *hw, u32 *data) 323 { 324 struct ngbe_hic_read_shadow_ram command; 325 s32 err; 326 int i; 327 328 command.hdr.req.cmd = FW_PHY_LED_CONF; 329 command.hdr.req.buf_lenh = 0; 330 command.hdr.req.buf_lenl = 0; 331 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM; 332 333 /* convert offset from words to bytes */ 334 command.address = 0; 335 /* one word */ 336 command.length = 0; 337 338 for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { 339 err = ngbe_host_interface_command(hw, (u32 *)&command, 340 sizeof(command), 341 NGBE_HI_COMMAND_TIMEOUT, true); 342 if (err) 343 continue; 344 345 command.hdr.rsp.ret_status &= 0x1F; 346 if (command.hdr.rsp.ret_status != 347 FW_CEM_RESP_STATUS_SUCCESS) 348 err = NGBE_ERR_HOST_INTERFACE_COMMAND; 349 350 break; 351 } 352 353 if (err) 354 return err; 355 356 if (command.address == FW_CHECKSUM_CAP_ST_PASS) { 357 *data = ((u32 *)&command)[2]; 358 err = 0; 359 } else if (command.address == FW_CHECKSUM_CAP_ST_FAIL) { 360 *data = FW_CHECKSUM_CAP_ST_FAIL; 361 err = -1; 362 } else { 363 err = NGBE_ERR_EEPROM_CHECKSUM; 364 } 365 366 return err; 367 } 368 369 s32 ngbe_hic_get_lldp(struct ngbe_hw *hw) 370 { 371 struct ngbe_hic_write_lldp buffer; 372 s32 err = 0; 373 374 buffer.hdr.cmd = FW_LLDP_GET_CMD; 375 buffer.hdr.buf_len = 0x1; 376 buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; 377 buffer.hdr.checksum = FW_DEFAULT_CHECKSUM; 378 buffer.func = hw->bus.lan_id; 379 380 err = ngbe_host_interface_command(hw, (u32 *)&buffer, sizeof(buffer), 381 NGBE_HI_COMMAND_TIMEOUT, true); 382 if (err) 383 return err; 384 385 if (buffer.hdr.cmd_or_resp.ret_status == FW_CEM_RESP_STATUS_SUCCESS) { 386 /* this field returns the status of LLDP */ 387 if (buffer.func) 388 hw->lldp_enabled = true; 389 else 390 hw->lldp_enabled = false; 391 } else { 392 err = NGBE_ERR_HOST_INTERFACE_COMMAND; 393 } 394 395 return err; 396 } 397 398 s32 ngbe_hic_set_lldp(struct ngbe_hw *hw, bool on) 399 { 400 struct ngbe_hic_write_lldp buffer; 401 402 if (on) 403 buffer.hdr.cmd = FW_LLDP_SET_CMD_ON; 404 else 405 buffer.hdr.cmd = FW_LLDP_SET_CMD_OFF; 406 buffer.hdr.buf_len = 0x1; 407 buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; 408 buffer.hdr.checksum = FW_DEFAULT_CHECKSUM; 409 buffer.func = hw->bus.lan_id; 410 411 return ngbe_host_interface_command(hw, (u32 *)&buffer, sizeof(buffer), 412 NGBE_HI_COMMAND_TIMEOUT, false); 413 } 414