1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2015-2020
3 */
4
5 #include "txgbe_type.h"
6 #include "txgbe_mng.h"
7
8 /**
9 * txgbe_calculate_checksum - Calculate checksum for buffer
10 * @buffer: pointer to EEPROM
11 * @length: size of EEPROM to calculate a checksum for
12 * Calculates the checksum for some buffer on a specified length. The
13 * checksum calculated is returned.
14 **/
15 static u8
txgbe_calculate_checksum(u8 * buffer,u32 length)16 txgbe_calculate_checksum(u8 *buffer, u32 length)
17 {
18 u32 i;
19 u8 sum = 0;
20
21 for (i = 0; i < length; i++)
22 sum += buffer[i];
23
24 return (u8)(0 - sum);
25 }
26
27 /**
28 * txgbe_hic_unlocked - Issue command to manageability block unlocked
29 * @hw: pointer to the HW structure
30 * @buffer: command to write and where the return status will be placed
31 * @length: length of buffer, must be multiple of 4 bytes
32 * @timeout: time in ms to wait for command completion
33 *
34 * Communicates with the manageability block. On success return 0
35 * else returns semaphore error when encountering an error acquiring
36 * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
37 *
38 * This function assumes that the TXGBE_MNGSEM_SWMBX semaphore is held
39 * by the caller.
40 **/
41 static s32
txgbe_hic_unlocked(struct txgbe_hw * hw,u32 * buffer,u32 length,u32 timeout)42 txgbe_hic_unlocked(struct txgbe_hw *hw, u32 *buffer, u32 length, u32 timeout)
43 {
44 u32 value, loop;
45 u16 i, dword_len;
46
47 DEBUGFUNC("txgbe_hic_unlocked");
48
49 if (!length || length > TXGBE_PMMBX_BSIZE) {
50 DEBUGOUT("Buffer length failure buffersize=%d.\n", length);
51 return TXGBE_ERR_HOST_INTERFACE_COMMAND;
52 }
53
54 /* Calculate length in DWORDs. We must be DWORD aligned */
55 if (length % sizeof(u32)) {
56 DEBUGOUT("Buffer length failure, not aligned to dword");
57 return TXGBE_ERR_INVALID_ARGUMENT;
58 }
59
60 dword_len = length >> 2;
61
62 /* The device driver writes the relevant command block
63 * into the ram area.
64 */
65 for (i = 0; i < dword_len; i++) {
66 wr32a(hw, TXGBE_MNGMBX, i, cpu_to_le32(buffer[i]));
67 buffer[i] = rd32a(hw, TXGBE_MNGMBX, i);
68 }
69 txgbe_flush(hw);
70
71 /* Setting this bit tells the ARC that a new command is pending. */
72 wr32m(hw, TXGBE_MNGMBXCTL,
73 TXGBE_MNGMBXCTL_SWRDY, TXGBE_MNGMBXCTL_SWRDY);
74
75 /* Check command completion */
76 loop = po32m(hw, TXGBE_MNGMBXCTL,
77 TXGBE_MNGMBXCTL_FWRDY, TXGBE_MNGMBXCTL_FWRDY,
78 &value, timeout, 1000);
79 if (!loop || !(value & TXGBE_MNGMBXCTL_FWACK)) {
80 DEBUGOUT("Command has failed with no status valid.\n");
81 return TXGBE_ERR_HOST_INTERFACE_COMMAND;
82 }
83
84 return 0;
85 }
86
87 /**
88 * txgbe_host_interface_command - Issue command to manageability block
89 * @hw: pointer to the HW structure
90 * @buffer: contains the command to write and where the return status will
91 * be placed
92 * @length: length of buffer, must be multiple of 4 bytes
93 * @timeout: time in ms to wait for command completion
94 * @return_data: read and return data from the buffer (true) or not (false)
95 * Needed because FW structures are big endian and decoding of
96 * these fields can be 8 bit or 16 bit based on command. Decoding
97 * is not easily understood without making a table of commands.
98 * So we will leave this up to the caller to read back the data
99 * in these cases.
100 *
101 * Communicates with the manageability block. On success return 0
102 * else returns semaphore error when encountering an error acquiring
103 * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
104 **/
105 static s32
txgbe_host_interface_command(struct txgbe_hw * hw,u32 * buffer,u32 length,u32 timeout,bool return_data)106 txgbe_host_interface_command(struct txgbe_hw *hw, u32 *buffer,
107 u32 length, u32 timeout, bool return_data)
108 {
109 u32 hdr_size = sizeof(struct txgbe_hic_hdr);
110 struct txgbe_hic_hdr *resp = (struct txgbe_hic_hdr *)buffer;
111 u16 buf_len;
112 s32 err;
113 u32 bi;
114 u32 dword_len;
115
116 DEBUGFUNC("txgbe_host_interface_command");
117
118 if (length == 0 || length > TXGBE_PMMBX_BSIZE) {
119 DEBUGOUT("Buffer length failure buffersize=%d.\n", length);
120 return TXGBE_ERR_HOST_INTERFACE_COMMAND;
121 }
122
123 /* Take management host interface semaphore */
124 err = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWMBX);
125 if (err)
126 return err;
127
128 err = txgbe_hic_unlocked(hw, buffer, length, timeout);
129 if (err)
130 goto rel_out;
131
132 if (!return_data)
133 goto rel_out;
134
135 /* Calculate length in DWORDs */
136 dword_len = hdr_size >> 2;
137
138 /* first pull in the header so we know the buffer length */
139 for (bi = 0; bi < dword_len; bi++)
140 buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi);
141
142 /*
143 * If there is any thing in data position pull it in
144 * Read Flash command requires reading buffer length from
145 * two byes instead of one byte
146 */
147 if (resp->cmd == 0x30) {
148 for (; bi < dword_len + 2; bi++)
149 buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi);
150
151 buf_len = (((u16)(resp->cmd_or_resp.ret_status) << 3)
152 & 0xF00) | resp->buf_len;
153 hdr_size += (2 << 2);
154 } else {
155 buf_len = resp->buf_len;
156 }
157 if (!buf_len)
158 goto rel_out;
159
160 if (length < buf_len + hdr_size) {
161 DEBUGOUT("Buffer not large enough for reply message.\n");
162 err = TXGBE_ERR_HOST_INTERFACE_COMMAND;
163 goto rel_out;
164 }
165
166 /* Calculate length in DWORDs, add 3 for odd lengths */
167 dword_len = (buf_len + 3) >> 2;
168
169 /* Pull in the rest of the buffer (bi is where we left off) */
170 for (; bi <= dword_len; bi++)
171 buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi);
172
173 rel_out:
174 hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWMBX);
175
176 return err;
177 }
178
179 /**
180 * txgbe_hic_sr_read - Read EEPROM word using a host interface cmd
181 * assuming that the semaphore is already obtained.
182 * @hw: pointer to hardware structure
183 * @offset: offset of word in the EEPROM to read
184 * @data: word read from the EEPROM
185 *
186 * Reads a 16 bit word from the EEPROM using the hostif.
187 **/
txgbe_hic_sr_read(struct txgbe_hw * hw,u32 addr,u8 * buf,int len)188 s32 txgbe_hic_sr_read(struct txgbe_hw *hw, u32 addr, u8 *buf, int len)
189 {
190 struct txgbe_hic_read_shadow_ram command;
191 u32 value;
192 int err, i = 0, j = 0;
193
194 if (len > TXGBE_PMMBX_DATA_SIZE)
195 return TXGBE_ERR_HOST_INTERFACE_COMMAND;
196
197 memset(&command, 0, sizeof(command));
198 command.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
199 command.hdr.req.buf_lenh = 0;
200 command.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
201 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
202 command.address = cpu_to_be32(addr);
203 command.length = cpu_to_be16(len);
204
205 err = txgbe_hic_unlocked(hw, (u32 *)&command,
206 sizeof(command), TXGBE_HI_COMMAND_TIMEOUT);
207 if (err)
208 return err;
209
210 while (i < (len >> 2)) {
211 value = rd32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i);
212 ((u32 *)buf)[i] = value;
213 i++;
214 }
215
216 value = rd32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i);
217 for (i <<= 2; i < len; i++)
218 ((u8 *)buf)[i] = ((u8 *)&value)[j++];
219
220 return 0;
221 }
222
223 /**
224 * txgbe_hic_sr_write - Write EEPROM word using hostif
225 * @hw: pointer to hardware structure
226 * @offset: offset of word in the EEPROM to write
227 * @data: word write to the EEPROM
228 *
229 * Write a 16 bit word to the EEPROM using the hostif.
230 **/
txgbe_hic_sr_write(struct txgbe_hw * hw,u32 addr,u8 * buf,int len)231 s32 txgbe_hic_sr_write(struct txgbe_hw *hw, u32 addr, u8 *buf, int len)
232 {
233 struct txgbe_hic_write_shadow_ram command;
234 u32 value;
235 int err = 0, i = 0, j = 0;
236
237 if (len > TXGBE_PMMBX_DATA_SIZE)
238 return TXGBE_ERR_HOST_INTERFACE_COMMAND;
239
240 memset(&command, 0, sizeof(command));
241 command.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
242 command.hdr.req.buf_lenh = 0;
243 command.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
244 command.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
245 command.address = cpu_to_be32(addr);
246 command.length = cpu_to_be16(len);
247
248 while (i < (len >> 2)) {
249 value = ((u32 *)buf)[i];
250 wr32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i, value);
251 i++;
252 }
253
254 for (i <<= 2; i < len; i++)
255 ((u8 *)&value)[j++] = ((u8 *)buf)[i];
256
257 wr32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + (i >> 2), value);
258
259 UNREFERENCED_PARAMETER(&command);
260
261 return err;
262 }
263
264 /**
265 * txgbe_hic_set_drv_ver - Sends driver version to firmware
266 * @hw: pointer to the HW structure
267 * @maj: driver version major number
268 * @min: driver version minor number
269 * @build: driver version build number
270 * @sub: driver version sub build number
271 * @len: unused
272 * @driver_ver: unused
273 *
274 * Sends driver version number to firmware through the manageability
275 * block. On success return 0
276 * else returns TXGBE_ERR_SWFW_SYNC when encountering an error acquiring
277 * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
278 **/
txgbe_hic_set_drv_ver(struct txgbe_hw * hw,u8 maj,u8 min,u8 build,u8 sub,u16 len,const char * driver_ver)279 s32 txgbe_hic_set_drv_ver(struct txgbe_hw *hw, u8 maj, u8 min,
280 u8 build, u8 sub, u16 len,
281 const char *driver_ver)
282 {
283 struct txgbe_hic_drv_info fw_cmd;
284 int i;
285 s32 ret_val = 0;
286
287 DEBUGFUNC("txgbe_hic_set_drv_ver");
288 UNREFERENCED_PARAMETER(len, driver_ver);
289
290 fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO;
291 fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN;
292 fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
293 fw_cmd.port_num = (u8)hw->bus.func;
294 fw_cmd.ver_maj = maj;
295 fw_cmd.ver_min = min;
296 fw_cmd.ver_build = build;
297 fw_cmd.ver_sub = sub;
298 fw_cmd.hdr.checksum = 0;
299 fw_cmd.pad = 0;
300 fw_cmd.pad2 = 0;
301 fw_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&fw_cmd,
302 (FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len));
303
304 for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
305 ret_val = txgbe_host_interface_command(hw, (u32 *)&fw_cmd,
306 sizeof(fw_cmd),
307 TXGBE_HI_COMMAND_TIMEOUT,
308 true);
309 if (ret_val != 0)
310 continue;
311
312 if (fw_cmd.hdr.cmd_or_resp.ret_status ==
313 FW_CEM_RESP_STATUS_SUCCESS)
314 ret_val = 0;
315 else
316 ret_val = TXGBE_ERR_HOST_INTERFACE_COMMAND;
317
318 break;
319 }
320
321 return ret_val;
322 }
323
324 /**
325 * txgbe_hic_reset - send reset cmd to fw
326 * @hw: pointer to hardware structure
327 *
328 * Sends reset cmd to firmware through the manageability
329 * block. On success return 0
330 * else returns TXGBE_ERR_SWFW_SYNC when encountering an error acquiring
331 * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
332 **/
333 s32
txgbe_hic_reset(struct txgbe_hw * hw)334 txgbe_hic_reset(struct txgbe_hw *hw)
335 {
336 struct txgbe_hic_reset reset_cmd;
337 int i;
338 s32 err = 0;
339
340 DEBUGFUNC("\n");
341
342 reset_cmd.hdr.cmd = FW_RESET_CMD;
343 reset_cmd.hdr.buf_len = FW_RESET_LEN;
344 reset_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
345 reset_cmd.lan_id = hw->bus.lan_id;
346 reset_cmd.reset_type = (u16)hw->reset_type;
347 reset_cmd.hdr.checksum = 0;
348 reset_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&reset_cmd,
349 (FW_CEM_HDR_LEN + reset_cmd.hdr.buf_len));
350
351 for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
352 err = txgbe_host_interface_command(hw, (u32 *)&reset_cmd,
353 sizeof(reset_cmd),
354 TXGBE_HI_COMMAND_TIMEOUT,
355 true);
356 if (err != 0)
357 continue;
358
359 if (reset_cmd.hdr.cmd_or_resp.ret_status ==
360 FW_CEM_RESP_STATUS_SUCCESS)
361 err = 0;
362 else
363 err = TXGBE_ERR_HOST_INTERFACE_COMMAND;
364
365 break;
366 }
367
368 return err;
369 }
370
371 /**
372 * txgbe_mng_present - returns true when management capability is present
373 * @hw: pointer to hardware structure
374 */
375 bool
txgbe_mng_present(struct txgbe_hw * hw)376 txgbe_mng_present(struct txgbe_hw *hw)
377 {
378 if (hw->mac.type == txgbe_mac_unknown)
379 return false;
380
381 return !!rd32m(hw, TXGBE_STAT, TXGBE_STAT_MNGINIT);
382 }
383
384 /**
385 * txgbe_mng_enabled - Is the manageability engine enabled?
386 * @hw: pointer to hardware structure
387 *
388 * Returns true if the manageability engine is enabled.
389 **/
390 bool
txgbe_mng_enabled(struct txgbe_hw * hw)391 txgbe_mng_enabled(struct txgbe_hw *hw)
392 {
393 UNREFERENCED_PARAMETER(hw);
394 /* firmware does not control laser */
395 return false;
396 }
397