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