xref: /dpdk/drivers/net/ngbe/base/ngbe_mng.c (revision 91e64c0e5d7ee7eaf39df9510bfc60bbcae14ca9)
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