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
ngbe_hic_unlocked(struct ngbe_hw * hw,u32 * buffer,u32 length,u32 timeout)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
ngbe_host_interface_command(struct ngbe_hw * hw,u32 * buffer,u32 length,u32 timeout,bool return_data)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 /*
121 * If there is any thing in data position pull it in
122 * Read Flash command requires reading buffer length from
123 * two byes instead of one byte
124 */
125 if (resp->cmd == 0x30) {
126 for (; bi < dword_len + 2; bi++)
127 buffer[bi] = rd32a(hw, NGBE_MNGMBX, bi);
128
129 buf_len = (((u16)(resp->cmd_or_resp.ret_status) << 3)
130 & 0xF00) | resp->buf_len;
131 hdr_size += (2 << 2);
132 } else {
133 buf_len = resp->buf_len;
134 }
135 if (!buf_len)
136 goto rel_out;
137
138 if (length < buf_len + hdr_size) {
139 DEBUGOUT("Buffer not large enough for reply message.");
140 err = NGBE_ERR_HOST_INTERFACE_COMMAND;
141 goto rel_out;
142 }
143
144 /* Calculate length in DWORDs, add 3 for odd lengths */
145 dword_len = (buf_len + 3) >> 2;
146
147 /* Pull in the rest of the buffer (bi is where we left off) */
148 for (; bi <= dword_len; bi++)
149 buffer[bi] = rd32a(hw, NGBE_MNGMBX, bi);
150
151 rel_out:
152 hw->mac.release_swfw_sync(hw, NGBE_MNGSEM_SWMBX);
153
154 return err;
155 }
156
157 /**
158 * ngbe_hic_sr_read - Read EEPROM word using a host interface cmd
159 * assuming that the semaphore is already obtained.
160 * @hw: pointer to hardware structure
161 * @offset: offset of word in the EEPROM to read
162 * @data: word read from the EEPROM
163 *
164 * Reads a 16 bit word from the EEPROM using the hostif.
165 **/
ngbe_hic_sr_read(struct ngbe_hw * hw,u32 addr,u8 * buf,int len)166 s32 ngbe_hic_sr_read(struct ngbe_hw *hw, u32 addr, u8 *buf, int len)
167 {
168 struct ngbe_hic_read_shadow_ram command;
169 u32 value;
170 int err, i = 0, j = 0;
171
172 if (len > NGBE_PMMBX_DATA_SIZE)
173 return NGBE_ERR_HOST_INTERFACE_COMMAND;
174
175 memset(&command, 0, sizeof(command));
176 command.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
177 command.hdr.req.buf_lenh = 0;
178 command.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
179 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
180 command.address = cpu_to_be32(addr);
181 command.length = cpu_to_be16(len);
182
183 err = ngbe_hic_unlocked(hw, (u32 *)&command,
184 sizeof(command), NGBE_HI_COMMAND_TIMEOUT);
185 if (err)
186 return err;
187
188 while (i < (len >> 2)) {
189 value = rd32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + i);
190 ((u32 *)buf)[i] = value;
191 i++;
192 }
193
194 value = rd32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + i);
195 for (i <<= 2; i < len; i++)
196 ((u8 *)buf)[i] = ((u8 *)&value)[j++];
197
198 return 0;
199 }
200
201 /**
202 * ngbe_hic_sr_write - Write EEPROM word using hostif
203 * @hw: pointer to hardware structure
204 * @offset: offset of word in the EEPROM to write
205 * @data: word write to the EEPROM
206 *
207 * Write a 16 bit word to the EEPROM using the hostif.
208 **/
ngbe_hic_sr_write(struct ngbe_hw * hw,u32 addr,u8 * buf,int len)209 s32 ngbe_hic_sr_write(struct ngbe_hw *hw, u32 addr, u8 *buf, int len)
210 {
211 struct ngbe_hic_write_shadow_ram command;
212 u32 value;
213 int err = 0, i = 0, j = 0;
214
215 if (len > NGBE_PMMBX_DATA_SIZE)
216 return NGBE_ERR_HOST_INTERFACE_COMMAND;
217
218 memset(&command, 0, sizeof(command));
219 command.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
220 command.hdr.req.buf_lenh = 0;
221 command.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
222 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
223 command.address = cpu_to_be32(addr);
224 command.length = cpu_to_be16(len);
225
226 while (i < (len >> 2)) {
227 value = ((u32 *)buf)[i];
228 wr32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + i, value);
229 i++;
230 }
231
232 for (i <<= 2; i < len; i++)
233 ((u8 *)&value)[j++] = ((u8 *)buf)[i];
234
235 wr32a(hw, NGBE_MNGMBX, FW_NVM_DATA_OFFSET + (i >> 2), value);
236
237 UNREFERENCED_PARAMETER(&command);
238
239 return err;
240 }
241
ngbe_hic_pcie_read(struct ngbe_hw * hw,u16 addr,u32 * buf,int len)242 s32 ngbe_hic_pcie_read(struct ngbe_hw *hw, u16 addr, u32 *buf, int len)
243 {
244 struct ngbe_hic_read_pcie command;
245 u32 value = 0;
246 int err, i = 0;
247
248 if (len > NGBE_PMMBX_DATA_SIZE)
249 return NGBE_ERR_HOST_INTERFACE_COMMAND;
250
251 memset(&command, 0, sizeof(command));
252 command.hdr.cmd = FW_PCIE_READ_CMD;
253 command.hdr.buf_len = sizeof(command) - sizeof(command.hdr);
254 command.hdr.checksum = FW_DEFAULT_CHECKSUM;
255 command.lan_id = hw->bus.lan_id;
256 command.addr = addr;
257
258 err = ngbe_host_interface_command(hw, (u32 *)&command,
259 sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false);
260 if (err)
261 return err;
262
263 while (i < (len >> 2)) {
264 value = rd32a(hw, NGBE_MNGMBX, FW_PCIE_BUSMASTER_OFFSET + i);
265 ((u32 *)buf)[i] = value;
266 i++;
267 }
268
269 return 0;
270 }
271
ngbe_hic_pcie_write(struct ngbe_hw * hw,u16 addr,u32 * buf,int len)272 s32 ngbe_hic_pcie_write(struct ngbe_hw *hw, u16 addr, u32 *buf, int len)
273 {
274 struct ngbe_hic_write_pcie command;
275 u32 value = 0;
276 int err, i = 0;
277
278 while (i < (len >> 2)) {
279 value = ((u32 *)buf)[i];
280 i++;
281 }
282
283 memset(&command, 0, sizeof(command));
284 command.hdr.cmd = FW_PCIE_WRITE_CMD;
285 command.hdr.buf_len = sizeof(command) - sizeof(command.hdr);
286 command.hdr.checksum = FW_DEFAULT_CHECKSUM;
287 command.lan_id = hw->bus.lan_id;
288 command.addr = addr;
289 command.data = value;
290
291 err = ngbe_host_interface_command(hw, (u32 *)&command,
292 sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false);
293 if (err)
294 return err;
295
296 return 0;
297 }
298
ngbe_hic_check_cap(struct ngbe_hw * hw)299 s32 ngbe_hic_check_cap(struct ngbe_hw *hw)
300 {
301 struct ngbe_hic_read_shadow_ram command;
302 s32 err;
303 int i;
304
305 command.hdr.req.cmd = FW_EEPROM_CHECK_STATUS;
306 command.hdr.req.buf_lenh = 0;
307 command.hdr.req.buf_lenl = 0;
308 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
309
310 /* convert offset from words to bytes */
311 command.address = 0;
312 /* one word */
313 command.length = 0;
314
315 for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
316 err = ngbe_host_interface_command(hw, (u32 *)&command,
317 sizeof(command),
318 NGBE_HI_COMMAND_TIMEOUT, true);
319 if (err)
320 continue;
321
322 command.hdr.rsp.ret_status &= 0x1F;
323 if (command.hdr.rsp.ret_status !=
324 FW_CEM_RESP_STATUS_SUCCESS)
325 err = NGBE_ERR_HOST_INTERFACE_COMMAND;
326
327 break;
328 }
329
330 if (!err && command.address != FW_CHECKSUM_CAP_ST_PASS)
331 err = NGBE_ERR_EEPROM_CHECKSUM;
332
333 return err;
334 }
335
ngbe_phy_led_oem_chk(struct ngbe_hw * hw,u32 * data)336 s32 ngbe_phy_led_oem_chk(struct ngbe_hw *hw, u32 *data)
337 {
338 struct ngbe_hic_read_shadow_ram command;
339 s32 err;
340 int i;
341
342 command.hdr.req.cmd = FW_PHY_LED_CONF;
343 command.hdr.req.buf_lenh = 0;
344 command.hdr.req.buf_lenl = 0;
345 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
346
347 /* convert offset from words to bytes */
348 command.address = 0;
349 /* one word */
350 command.length = 0;
351
352 for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
353 err = ngbe_host_interface_command(hw, (u32 *)&command,
354 sizeof(command),
355 NGBE_HI_COMMAND_TIMEOUT, true);
356 if (err)
357 continue;
358
359 command.hdr.rsp.ret_status &= 0x1F;
360 if (command.hdr.rsp.ret_status !=
361 FW_CEM_RESP_STATUS_SUCCESS)
362 err = NGBE_ERR_HOST_INTERFACE_COMMAND;
363
364 break;
365 }
366
367 if (err)
368 return err;
369
370 if (command.address == FW_CHECKSUM_CAP_ST_PASS) {
371 *data = ((u32 *)&command)[2];
372 err = 0;
373 } else if (command.address == FW_CHECKSUM_CAP_ST_FAIL) {
374 *data = FW_CHECKSUM_CAP_ST_FAIL;
375 err = -1;
376 } else {
377 err = NGBE_ERR_EEPROM_CHECKSUM;
378 }
379
380 return err;
381 }
382