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