Branch data Line data Source code
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 : 0 : 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 [ # # ]: 0 : if (!length || length > NGBE_PMMBX_BSIZE) {
30 : 0 : DEBUGOUT("Buffer length failure buffersize=%d.", length);
31 : 0 : return NGBE_ERR_HOST_INTERFACE_COMMAND;
32 : : }
33 : :
34 : : /* Calculate length in DWORDs. We must be DWORD aligned */
35 [ # # ]: 0 : if (length % sizeof(u32)) {
36 : 0 : DEBUGOUT("Buffer length failure, not aligned to dword");
37 : 0 : return NGBE_ERR_INVALID_ARGUMENT;
38 : : }
39 : :
40 : 0 : dword_len = length >> 2;
41 : :
42 : : /* The device driver writes the relevant command block
43 : : * into the ram area.
44 : : */
45 [ # # ]: 0 : for (i = 0; i < dword_len; i++) {
46 : 0 : wr32a(hw, NGBE_MNGMBX, i, cpu_to_le32(buffer[i]));
47 : 0 : 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 : 0 : loop = po32m(hw, NGBE_MNGMBXCTL,
57 : : NGBE_MNGMBXCTL_FWRDY, NGBE_MNGMBXCTL_FWRDY,
58 : : &value, timeout, 1000);
59 [ # # # # ]: 0 : if (!loop || !(value & NGBE_MNGMBXCTL_FWACK)) {
60 : 0 : DEBUGOUT("Command has failed with no status valid.");
61 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (length == 0 || length > NGBE_PMMBX_BSIZE) {
97 : 0 : DEBUGOUT("Buffer length failure buffersize=%d.", length);
98 : 0 : return NGBE_ERR_HOST_INTERFACE_COMMAND;
99 : : }
100 : :
101 : : /* Take management host interface semaphore */
102 : 0 : err = hw->mac.acquire_swfw_sync(hw, NGBE_MNGSEM_SWMBX);
103 [ # # ]: 0 : if (err)
104 : : return err;
105 : :
106 : 0 : err = ngbe_hic_unlocked(hw, buffer, length, timeout);
107 [ # # ]: 0 : if (err)
108 : 0 : goto rel_out;
109 : :
110 [ # # ]: 0 : if (!return_data)
111 : 0 : 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 [ # # ]: 0 : for (bi = 0; bi < dword_len; bi++)
118 : 0 : buffer[bi] = rd32a(hw, NGBE_MNGMBX, bi);
119 : :
120 : 0 : buf_len = resp->buf_len;
121 [ # # ]: 0 : if (!buf_len)
122 : 0 : goto rel_out;
123 : :
124 [ # # ]: 0 : if (length < buf_len + hdr_size) {
125 : 0 : DEBUGOUT("Buffer not large enough for reply message.");
126 : : err = NGBE_ERR_HOST_INTERFACE_COMMAND;
127 : 0 : goto rel_out;
128 : : }
129 : :
130 : : /* Calculate length in DWORDs, add 3 for odd lengths */
131 : 0 : dword_len = (buf_len + 3) >> 2;
132 : :
133 : : /* Pull in the rest of the buffer (bi is where we left off) */
134 [ # # ]: 0 : for (; bi <= dword_len; bi++)
135 : 0 : buffer[bi] = rd32a(hw, NGBE_MNGMBX, bi);
136 : :
137 : 0 : rel_out:
138 : 0 : hw->mac.release_swfw_sync(hw, NGBE_MNGSEM_SWMBX);
139 : :
140 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (len > NGBE_PMMBX_DATA_SIZE)
159 : : return NGBE_ERR_HOST_INTERFACE_COMMAND;
160 : :
161 : : memset(&command, 0, sizeof(command));
162 : 0 : command.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
163 : : command.hdr.req.buf_lenh = 0;
164 : 0 : command.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
165 : 0 : command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
166 [ # # ]: 0 : command.address = cpu_to_be32(addr);
167 [ # # ]: 0 : command.length = cpu_to_be16(len);
168 : :
169 : 0 : err = ngbe_hic_unlocked(hw, (u32 *)&command,
170 : : sizeof(command), NGBE_HI_COMMAND_TIMEOUT);
171 [ # # ]: 0 : if (err)
172 : : return err;
173 : :
174 [ # # ]: 0 : while (i < (len >> 2)) {
175 : 0 : value = rd32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + i);
176 : 0 : ((u32 *)buf)[i] = value;
177 : 0 : i++;
178 : : }
179 : :
180 : 0 : value = rd32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + i);
181 [ # # ]: 0 : for (i <<= 2; i < len; i++)
182 : 0 : ((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 : 0 : 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 [ # # ]: 0 : if (len > NGBE_PMMBX_DATA_SIZE)
202 : : return NGBE_ERR_HOST_INTERFACE_COMMAND;
203 : :
204 : : memset(&command, 0, sizeof(command));
205 : 0 : command.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
206 : : command.hdr.req.buf_lenh = 0;
207 : 0 : command.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
208 : 0 : command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
209 [ # # ]: 0 : command.address = cpu_to_be32(addr);
210 [ # # ]: 0 : command.length = cpu_to_be16(len);
211 : :
212 [ # # ]: 0 : while (i < (len >> 2)) {
213 : 0 : value = ((u32 *)buf)[i];
214 : 0 : wr32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + i, value);
215 : 0 : i++;
216 : : }
217 : :
218 [ # # ]: 0 : for (i <<= 2; i < len; i++)
219 : 0 : ((u8 *)&value)[j++] = ((u8 *)buf)[i];
220 : :
221 : 0 : wr32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + (i >> 2), value);
222 : :
223 : : UNREFERENCED_PARAMETER(&command);
224 : :
225 : 0 : return err;
226 : : }
227 : :
228 : 0 : 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 [ # # ]: 0 : if (len > NGBE_PMMBX_DATA_SIZE)
235 : : return NGBE_ERR_HOST_INTERFACE_COMMAND;
236 : :
237 : : memset(&command, 0, sizeof(command));
238 : 0 : command.hdr.cmd = FW_PCIE_READ_CMD;
239 : 0 : command.hdr.buf_len = sizeof(command) - sizeof(command.hdr);
240 : 0 : command.hdr.checksum = FW_DEFAULT_CHECKSUM;
241 : 0 : command.lan_id = hw->bus.lan_id;
242 : 0 : command.addr = addr;
243 : :
244 : 0 : err = ngbe_host_interface_command(hw, (u32 *)&command,
245 : : sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false);
246 [ # # ]: 0 : if (err)
247 : : return err;
248 : :
249 [ # # ]: 0 : while (i < (len >> 2)) {
250 : 0 : value = rd32a(hw, NGBE_MNGMBX, FW_PCIE_BUSMASTER_OFFSET + i);
251 : 0 : ((u32 *)buf)[i] = value;
252 : 0 : i++;
253 : : }
254 : :
255 : : return 0;
256 : : }
257 : :
258 : 0 : 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 [ # # ]: 0 : while (i < (len >> 2)) {
265 : 0 : value = ((u32 *)buf)[i];
266 : 0 : i++;
267 : : }
268 : :
269 : : memset(&command, 0, sizeof(command));
270 : 0 : command.hdr.cmd = FW_PCIE_WRITE_CMD;
271 : 0 : command.hdr.buf_len = sizeof(command) - sizeof(command.hdr);
272 : 0 : command.hdr.checksum = FW_DEFAULT_CHECKSUM;
273 : 0 : command.lan_id = hw->bus.lan_id;
274 : 0 : command.addr = addr;
275 : 0 : command.data = value;
276 : :
277 : 0 : err = ngbe_host_interface_command(hw, (u32 *)&command,
278 : : sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false);
279 [ # # ]: 0 : if (err)
280 : 0 : return err;
281 : :
282 : : return 0;
283 : : }
284 : :
285 : 0 : 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 : 0 : command.hdr.req.cmd = FW_EEPROM_CHECK_STATUS;
292 : 0 : command.hdr.req.buf_lenh = 0;
293 : 0 : command.hdr.req.buf_lenl = 0;
294 : 0 : command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
295 : :
296 : : /* convert offset from words to bytes */
297 : 0 : command.address = 0;
298 : : /* one word */
299 : 0 : command.length = 0;
300 : :
301 [ # # ]: 0 : for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
302 : 0 : err = ngbe_host_interface_command(hw, (u32 *)&command,
303 : : sizeof(command),
304 : : NGBE_HI_COMMAND_TIMEOUT, true);
305 [ # # ]: 0 : if (err)
306 : : continue;
307 : :
308 : 0 : command.hdr.rsp.ret_status &= 0x1F;
309 [ # # ]: 0 : 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 [ # # # # ]: 0 : if (!err && command.address != FW_CHECKSUM_CAP_ST_PASS)
317 : : err = NGBE_ERR_EEPROM_CHECKSUM;
318 : :
319 : 0 : return err;
320 : : }
321 : :
322 : 0 : 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 : 0 : command.hdr.req.cmd = FW_PHY_LED_CONF;
329 : 0 : command.hdr.req.buf_lenh = 0;
330 : 0 : command.hdr.req.buf_lenl = 0;
331 : 0 : command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
332 : :
333 : : /* convert offset from words to bytes */
334 : 0 : command.address = 0;
335 : : /* one word */
336 : 0 : command.length = 0;
337 : :
338 [ # # ]: 0 : for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
339 : 0 : err = ngbe_host_interface_command(hw, (u32 *)&command,
340 : : sizeof(command),
341 : : NGBE_HI_COMMAND_TIMEOUT, true);
342 [ # # ]: 0 : if (err)
343 : : continue;
344 : :
345 : 0 : command.hdr.rsp.ret_status &= 0x1F;
346 [ # # ]: 0 : 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 [ # # ]: 0 : if (err)
354 : 0 : return err;
355 : :
356 [ # # ]: 0 : if (command.address == FW_CHECKSUM_CAP_ST_PASS) {
357 : 0 : *data = ((u32 *)&command)[2];
358 : : err = 0;
359 [ # # ]: 0 : } else if (command.address == FW_CHECKSUM_CAP_ST_FAIL) {
360 : 0 : *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 : 0 : s32 ngbe_hic_get_lldp(struct ngbe_hw *hw)
370 : : {
371 : : struct ngbe_hic_write_lldp buffer;
372 : : s32 err = 0;
373 : :
374 : 0 : buffer.hdr.cmd = FW_LLDP_GET_CMD;
375 : 0 : buffer.hdr.buf_len = 0x1;
376 : 0 : buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
377 : 0 : buffer.hdr.checksum = FW_DEFAULT_CHECKSUM;
378 : 0 : buffer.func = hw->bus.lan_id;
379 : :
380 : 0 : err = ngbe_host_interface_command(hw, (u32 *)&buffer, sizeof(buffer),
381 : : NGBE_HI_COMMAND_TIMEOUT, true);
382 [ # # ]: 0 : if (err)
383 : : return err;
384 : :
385 [ # # ]: 0 : if (buffer.hdr.cmd_or_resp.ret_status == FW_CEM_RESP_STATUS_SUCCESS) {
386 : : /* this field returns the status of LLDP */
387 [ # # ]: 0 : if (buffer.func)
388 : 0 : hw->lldp_enabled = true;
389 : : else
390 : 0 : hw->lldp_enabled = false;
391 : : } else {
392 : : err = NGBE_ERR_HOST_INTERFACE_COMMAND;
393 : : }
394 : :
395 : : return err;
396 : : }
397 : :
398 : 0 : s32 ngbe_hic_set_lldp(struct ngbe_hw *hw, bool on)
399 : : {
400 : : struct ngbe_hic_write_lldp buffer;
401 : :
402 [ # # ]: 0 : if (on)
403 : 0 : buffer.hdr.cmd = FW_LLDP_SET_CMD_ON;
404 : : else
405 : 0 : buffer.hdr.cmd = FW_LLDP_SET_CMD_OFF;
406 : 0 : buffer.hdr.buf_len = 0x1;
407 : 0 : buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
408 : 0 : buffer.hdr.checksum = FW_DEFAULT_CHECKSUM;
409 : 0 : buffer.func = hw->bus.lan_id;
410 : :
411 : 0 : return ngbe_host_interface_command(hw, (u32 *)&buffer, sizeof(buffer),
412 : : NGBE_HI_COMMAND_TIMEOUT, false);
413 : : }
|