pipeline: add check against loops
[dpdk.git] / drivers / net / ngbe / base / ngbe_mng.c
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_pcie_read(struct ngbe_hw *hw, u16 addr, u32 *buf, int len)
247 {
248         struct ngbe_hic_read_pcie command;
249         u32 value = 0;
250         int err, i = 0;
251
252         if (len > NGBE_PMMBX_DATA_SIZE)
253                 return NGBE_ERR_HOST_INTERFACE_COMMAND;
254
255         memset(&command, 0, sizeof(command));
256         command.hdr.cmd = FW_PCIE_READ_CMD;
257         command.hdr.buf_len = sizeof(command) - sizeof(command.hdr);
258         command.hdr.checksum = FW_DEFAULT_CHECKSUM;
259         command.lan_id = hw->bus.lan_id;
260         command.addr = addr;
261
262         err = ngbe_host_interface_command(hw, (u32 *)&command,
263                         sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false);
264         if (err)
265                 return err;
266
267         while (i < (len >> 2)) {
268                 value = rd32a(hw, NGBE_MNGMBX, FW_PCIE_BUSMASTER_OFFSET + i);
269                 ((u32 *)buf)[i] = value;
270                 i++;
271         }
272
273         return 0;
274 }
275
276 s32 ngbe_hic_pcie_write(struct ngbe_hw *hw, u16 addr, u32 *buf, int len)
277 {
278         struct ngbe_hic_write_pcie command;
279         u32 value = 0;
280         int err, i = 0;
281
282         while (i < (len >> 2)) {
283                 value = ((u32 *)buf)[i];
284                 i++;
285         }
286
287         memset(&command, 0, sizeof(command));
288         command.hdr.cmd = FW_PCIE_WRITE_CMD;
289         command.hdr.buf_len = sizeof(command) - sizeof(command.hdr);
290         command.hdr.checksum = FW_DEFAULT_CHECKSUM;
291         command.lan_id = hw->bus.lan_id;
292         command.addr = addr;
293         command.data = value;
294
295         err = ngbe_host_interface_command(hw, (u32 *)&command,
296                         sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false);
297         if (err)
298                 return err;
299
300         return 0;
301 }
302
303 s32 ngbe_hic_check_cap(struct ngbe_hw *hw)
304 {
305         struct ngbe_hic_read_shadow_ram command;
306         s32 err;
307         int i;
308
309         DEBUGFUNC("\n");
310
311         command.hdr.req.cmd = FW_EEPROM_CHECK_STATUS;
312         command.hdr.req.buf_lenh = 0;
313         command.hdr.req.buf_lenl = 0;
314         command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
315
316         /* convert offset from words to bytes */
317         command.address = 0;
318         /* one word */
319         command.length = 0;
320
321         for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
322                 err = ngbe_host_interface_command(hw, (u32 *)&command,
323                                 sizeof(command),
324                                 NGBE_HI_COMMAND_TIMEOUT, true);
325                 if (err)
326                         continue;
327
328                 command.hdr.rsp.ret_status &= 0x1F;
329                 if (command.hdr.rsp.ret_status !=
330                         FW_CEM_RESP_STATUS_SUCCESS)
331                         err = NGBE_ERR_HOST_INTERFACE_COMMAND;
332
333                 break;
334         }
335
336         if (!err && command.address != FW_CHECKSUM_CAP_ST_PASS)
337                 err = NGBE_ERR_EEPROM_CHECKSUM;
338
339         return err;
340 }
341
342 s32 ngbe_phy_led_oem_chk(struct ngbe_hw *hw, u32 *data)
343 {
344         struct ngbe_hic_read_shadow_ram command;
345         s32 err;
346         int i;
347
348         DEBUGFUNC("\n");
349
350         command.hdr.req.cmd = FW_PHY_LED_CONF;
351         command.hdr.req.buf_lenh = 0;
352         command.hdr.req.buf_lenl = 0;
353         command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
354
355         /* convert offset from words to bytes */
356         command.address = 0;
357         /* one word */
358         command.length = 0;
359
360         for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
361                 err = ngbe_host_interface_command(hw, (u32 *)&command,
362                                 sizeof(command),
363                                 NGBE_HI_COMMAND_TIMEOUT, true);
364                 if (err)
365                         continue;
366
367                 command.hdr.rsp.ret_status &= 0x1F;
368                 if (command.hdr.rsp.ret_status !=
369                         FW_CEM_RESP_STATUS_SUCCESS)
370                         err = NGBE_ERR_HOST_INTERFACE_COMMAND;
371
372                 break;
373         }
374
375         if (err)
376                 return err;
377
378         if (command.address == FW_CHECKSUM_CAP_ST_PASS) {
379                 *data = ((u32 *)&command)[2];
380                 err = 0;
381         } else if (command.address == FW_CHECKSUM_CAP_ST_FAIL) {
382                 *data = FW_CHECKSUM_CAP_ST_FAIL;
383                 err = -1;
384         } else {
385                 err = NGBE_ERR_EEPROM_CHECKSUM;
386         }
387
388         return err;
389 }