Branch data Line data Source code
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 [ # # # # ]: 0 : for (i = 0; i < length; i++)
23 : 0 : sum += buffer[i];
24 : :
25 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (!length || length > TXGBE_PMMBX_BSIZE) {
49 : 0 : DEBUGOUT("Buffer length failure buffersize=%d.", length);
50 : 0 : return TXGBE_ERR_HOST_INTERFACE_COMMAND;
51 : : }
52 : :
53 : : /* Calculate length in DWORDs. We must be DWORD aligned */
54 [ # # ]: 0 : if (length % sizeof(u32)) {
55 : 0 : DEBUGOUT("Buffer length failure, not aligned to dword");
56 : 0 : return TXGBE_ERR_INVALID_ARGUMENT;
57 : : }
58 : :
59 [ # # # ]: 0 : 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 [ # # ]: 0 : for (i = 0; i < dword_len; i++) {
66 : 0 : wr32a(hw, TXGBE_MNGMBX, i, cpu_to_le32(buffer[i]));
67 : 0 : 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 : 0 : loop = po32m(hw, TXGBE_MNGMBXCTL,
77 : : TXGBE_MNGMBXCTL_FWRDY, TXGBE_MNGMBXCTL_FWRDY,
78 : : &value, timeout, 1000);
79 [ # # # # ]: 0 : if (!loop || !(value & TXGBE_MNGMBXCTL_FWACK)) {
80 : 0 : DEBUGOUT("Command has failed with no status valid.");
81 : 0 : return TXGBE_ERR_HOST_INTERFACE_COMMAND;
82 : : }
83 : :
84 [ # # ]: 0 : if ((rd32(hw, TXGBE_MNGMBX) & 0xff0000) >> 16 == 0x80) {
85 : 0 : DEBUGOUT("It's unknown command.");
86 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (length == 0 || length > TXGBE_PMMBX_BSIZE) {
122 : 0 : DEBUGOUT("Buffer length failure buffersize=%d.", length);
123 : 0 : return TXGBE_ERR_HOST_INTERFACE_COMMAND;
124 : : }
125 : :
126 : : /* Take management host interface semaphore */
127 : 0 : err = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWMBX);
128 [ # # ]: 0 : if (err)
129 : : return err;
130 : :
131 : 0 : err = txgbe_hic_unlocked(hw, buffer, length, timeout);
132 [ # # ]: 0 : if (err)
133 : 0 : goto rel_out;
134 : :
135 [ # # ]: 0 : if (!return_data)
136 : 0 : 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 [ # # ]: 0 : for (bi = 0; bi < dword_len; bi++)
143 : 0 : buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi);
144 : :
145 : 0 : buf_len = resp->buf_len;
146 [ # # ]: 0 : if (!buf_len)
147 : 0 : goto rel_out;
148 : :
149 [ # # ]: 0 : if (length < buf_len + hdr_size) {
150 : 0 : DEBUGOUT("Buffer not large enough for reply message.");
151 : : err = TXGBE_ERR_HOST_INTERFACE_COMMAND;
152 : 0 : goto rel_out;
153 : : }
154 : :
155 : : /* Calculate length in DWORDs, add 3 for odd lengths */
156 : 0 : dword_len = (buf_len + 3) >> 2;
157 : :
158 : : /* Pull in the rest of the buffer (bi is where we left off) */
159 [ # # ]: 0 : for (; bi <= dword_len; bi++)
160 : 0 : buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi);
161 : :
162 : 0 : rel_out:
163 : 0 : hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWMBX);
164 : :
165 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (len > TXGBE_PMMBX_DATA_SIZE)
184 : : return TXGBE_ERR_HOST_INTERFACE_COMMAND;
185 : :
186 : : memset(&command, 0, sizeof(command));
187 : 0 : command.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
188 : : command.hdr.req.buf_lenh = 0;
189 : 0 : command.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
190 : 0 : command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
191 [ # # ]: 0 : command.address = cpu_to_be32(addr);
192 [ # # ]: 0 : command.length = cpu_to_be16(len);
193 : :
194 : 0 : err = txgbe_hic_unlocked(hw, (u32 *)&command,
195 : : sizeof(command), TXGBE_HI_COMMAND_TIMEOUT);
196 [ # # ]: 0 : if (err)
197 : : return err;
198 : :
199 [ # # ]: 0 : while (i < (len >> 2)) {
200 : 0 : value = rd32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i);
201 : 0 : ((u32 *)buf)[i] = value;
202 : 0 : i++;
203 : : }
204 : :
205 : 0 : value = rd32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i);
206 [ # # ]: 0 : for (i <<= 2; i < len; i++)
207 : 0 : ((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 : 0 : 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 [ # # ]: 0 : if (len > TXGBE_PMMBX_DATA_SIZE)
227 : : return TXGBE_ERR_HOST_INTERFACE_COMMAND;
228 : :
229 : : memset(&command, 0, sizeof(command));
230 : 0 : command.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
231 : : command.hdr.req.buf_lenh = 0;
232 : 0 : command.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
233 : 0 : command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
234 [ # # ]: 0 : command.address = cpu_to_be32(addr);
235 [ # # ]: 0 : command.length = cpu_to_be16(len);
236 : :
237 [ # # ]: 0 : while (i < (len >> 2)) {
238 : 0 : value = ((u32 *)buf)[i];
239 : 0 : wr32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i, value);
240 : 0 : i++;
241 : : }
242 : :
243 [ # # ]: 0 : for (i <<= 2; i < len; i++)
244 : 0 : ((u8 *)&value)[j++] = ((u8 *)buf)[i];
245 : :
246 : 0 : wr32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + (i >> 2), value);
247 : :
248 : : UNREFERENCED_PARAMETER(&command);
249 : :
250 : 0 : return err;
251 : : }
252 : :
253 : 0 : 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 : 0 : buffer.hdr.req.cmd = FW_DW_CLOSE_NOTIFY;
260 : 0 : buffer.hdr.req.buf_lenh = 0;
261 : 0 : buffer.hdr.req.buf_lenl = 0;
262 : 0 : buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
263 : :
264 : : /* one word */
265 : 0 : buffer.length = 0;
266 : 0 : buffer.address = 0;
267 : :
268 : 0 : status = txgbe_host_interface_command(hw, (u32 *)&buffer,
269 : : sizeof(buffer),
270 : : TXGBE_HI_COMMAND_TIMEOUT, false);
271 [ # # ]: 0 : if (status)
272 : : return status;
273 : :
274 : : tmp = rd32a(hw, TXGBE_MNGMBX, 1);
275 [ # # ]: 0 : 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 : 0 : 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 : 0 : buffer.hdr.req.cmd = FW_DW_OPEN_NOTIFY;
290 : 0 : buffer.hdr.req.buf_lenh = 0;
291 : 0 : buffer.hdr.req.buf_lenl = 0;
292 : 0 : buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
293 : :
294 : : /* one word */
295 : 0 : buffer.length = 0;
296 : 0 : buffer.address = 0;
297 : :
298 : 0 : status = txgbe_host_interface_command(hw, (u32 *)&buffer,
299 : : sizeof(buffer),
300 : : TXGBE_HI_COMMAND_TIMEOUT, false);
301 [ # # ]: 0 : if (status)
302 : : return status;
303 : :
304 : : tmp = rd32a(hw, TXGBE_MNGMBX, 1);
305 [ # # ]: 0 : 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 : 0 : 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 : 0 : fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO;
339 : 0 : fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN;
340 : 0 : fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
341 : 0 : fw_cmd.port_num = (u8)hw->bus.func;
342 : 0 : fw_cmd.ver_maj = maj;
343 : 0 : fw_cmd.ver_min = min;
344 : 0 : fw_cmd.ver_build = build;
345 : 0 : fw_cmd.ver_sub = sub;
346 : 0 : fw_cmd.hdr.checksum = 0;
347 : 0 : fw_cmd.pad = 0;
348 : 0 : fw_cmd.pad2 = 0;
349 : 0 : fw_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&fw_cmd,
350 : : (FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len));
351 : :
352 [ # # ]: 0 : for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
353 : 0 : ret_val = txgbe_host_interface_command(hw, (u32 *)&fw_cmd,
354 : : sizeof(fw_cmd),
355 : : TXGBE_HI_COMMAND_TIMEOUT,
356 : : true);
357 [ # # ]: 0 : if (ret_val != 0)
358 : : continue;
359 : :
360 [ # # ]: 0 : 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 : 0 : 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 : 0 : txgbe_hic_reset(struct txgbe_hw *hw)
383 : : {
384 : : struct txgbe_hic_reset reset_cmd;
385 : : int i;
386 : : s32 err = 0;
387 : :
388 : 0 : reset_cmd.hdr.cmd = FW_RESET_CMD;
389 : 0 : reset_cmd.hdr.buf_len = FW_RESET_LEN;
390 : 0 : reset_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
391 : 0 : reset_cmd.lan_id = hw->bus.lan_id;
392 : 0 : reset_cmd.reset_type = (u16)hw->reset_type;
393 : 0 : reset_cmd.hdr.checksum = 0;
394 : 0 : reset_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&reset_cmd,
395 : : (FW_CEM_HDR_LEN + reset_cmd.hdr.buf_len));
396 : :
397 [ # # ]: 0 : for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
398 : 0 : err = txgbe_host_interface_command(hw, (u32 *)&reset_cmd,
399 : : sizeof(reset_cmd),
400 : : TXGBE_HI_COMMAND_TIMEOUT,
401 : : true);
402 [ # # ]: 0 : if (err != 0)
403 : : continue;
404 : :
405 [ # # ]: 0 : 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 : 0 : 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 : 0 : txgbe_mng_present(struct txgbe_hw *hw)
423 : : {
424 [ # # ]: 0 : if (hw->mac.type == txgbe_mac_unknown)
425 : : return false;
426 : :
427 : 0 : 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 : 0 : txgbe_mng_enabled(struct txgbe_hw *hw)
438 : : {
439 : : UNREFERENCED_PARAMETER(hw);
440 : : /* firmware does not control laser */
441 : 0 : return false;
442 : : }
443 : :
444 : 0 : s32 txgbe_hic_get_lldp(struct txgbe_hw *hw)
445 : : {
446 : : struct txgbe_hic_write_lldp buffer;
447 : : s32 err = 0;
448 : :
449 : 0 : buffer.hdr.cmd = FW_LLDP_GET_CMD;
450 : 0 : buffer.hdr.buf_len = 0x1;
451 : 0 : buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
452 : 0 : buffer.hdr.checksum = FW_DEFAULT_CHECKSUM;
453 : 0 : buffer.func = hw->bus.lan_id;
454 : :
455 : 0 : err = txgbe_host_interface_command(hw, (u32 *)&buffer, sizeof(buffer),
456 : : TXGBE_HI_COMMAND_TIMEOUT, true);
457 [ # # ]: 0 : if (err)
458 : : return err;
459 : :
460 [ # # ]: 0 : if (buffer.hdr.cmd_or_resp.ret_status == FW_CEM_RESP_STATUS_SUCCESS) {
461 : : /* this field returns the status of LLDP */
462 [ # # ]: 0 : if (buffer.func)
463 : 0 : hw->lldp_enabled = true;
464 : : else
465 : 0 : hw->lldp_enabled = false;
466 : : } else {
467 : : err = TXGBE_ERR_HOST_INTERFACE_COMMAND;
468 : : }
469 : :
470 : : return err;
471 : : }
472 : :
473 : 0 : s32 txgbe_hic_set_lldp(struct txgbe_hw *hw, bool on)
474 : : {
475 : : struct txgbe_hic_write_lldp buffer;
476 : :
477 [ # # ]: 0 : if (on)
478 : 0 : buffer.hdr.cmd = FW_LLDP_SET_CMD_ON;
479 : : else
480 : 0 : buffer.hdr.cmd = FW_LLDP_SET_CMD_OFF;
481 : 0 : buffer.hdr.buf_len = 0x1;
482 : 0 : buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
483 : 0 : buffer.hdr.checksum = FW_DEFAULT_CHECKSUM;
484 : 0 : buffer.func = hw->bus.lan_id;
485 : :
486 : 0 : return txgbe_host_interface_command(hw, (u32 *)&buffer, sizeof(buffer),
487 : : TXGBE_HI_COMMAND_TIMEOUT, false);
488 : : }
|