xref: /dpdk/drivers/net/ngbe/base/ngbe_mng.c (revision b53d106d34b5c638f5a2cbdfee0da5bd42d4383f)
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_check_cap(struct ngbe_hw *hw)
247 {
248 	struct ngbe_hic_read_shadow_ram command;
249 	s32 err;
250 	int i;
251 
252 	DEBUGFUNC("\n");
253 
254 	command.hdr.req.cmd = FW_EEPROM_CHECK_STATUS;
255 	command.hdr.req.buf_lenh = 0;
256 	command.hdr.req.buf_lenl = 0;
257 	command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
258 
259 	/* convert offset from words to bytes */
260 	command.address = 0;
261 	/* one word */
262 	command.length = 0;
263 
264 	for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
265 		err = ngbe_host_interface_command(hw, (u32 *)&command,
266 				sizeof(command),
267 				NGBE_HI_COMMAND_TIMEOUT, true);
268 		if (err)
269 			continue;
270 
271 		command.hdr.rsp.ret_status &= 0x1F;
272 		if (command.hdr.rsp.ret_status !=
273 			FW_CEM_RESP_STATUS_SUCCESS)
274 			err = NGBE_ERR_HOST_INTERFACE_COMMAND;
275 
276 		break;
277 	}
278 
279 	if (!err && command.address != FW_CHECKSUM_CAP_ST_PASS)
280 		err = NGBE_ERR_EEPROM_CHECKSUM;
281 
282 	return err;
283 }
284