1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) |
2 | /* QLogic qed NIC Driver |
3 | * Copyright (c) 2015-2017 QLogic Corporation |
4 | * Copyright (c) 2019-2020 Marvell International Ltd. |
5 | */ |
6 | |
7 | #include <linux/types.h> |
8 | #include <linux/io.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/errno.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/string.h> |
14 | #include "qed.h" |
15 | #include "qed_hsi.h" |
16 | #include "qed_hw.h" |
17 | #include "qed_init_ops.h" |
18 | #include "qed_iro_hsi.h" |
19 | #include "qed_reg_addr.h" |
20 | #include "qed_sriov.h" |
21 | |
22 | #define QED_INIT_MAX_POLL_COUNT 100 |
23 | #define QED_INIT_POLL_PERIOD_US 500 |
24 | |
25 | static u32 pxp_global_win[] = { |
26 | 0, |
27 | 0, |
28 | 0x1c02, /* win 2: addr=0x1c02000, size=4096 bytes */ |
29 | 0x1c80, /* win 3: addr=0x1c80000, size=4096 bytes */ |
30 | 0x1d00, /* win 4: addr=0x1d00000, size=4096 bytes */ |
31 | 0x1d01, /* win 5: addr=0x1d01000, size=4096 bytes */ |
32 | 0x1d02, /* win 6: addr=0x1d02000, size=4096 bytes */ |
33 | 0x1d80, /* win 7: addr=0x1d80000, size=4096 bytes */ |
34 | 0x1d81, /* win 8: addr=0x1d81000, size=4096 bytes */ |
35 | 0x1d82, /* win 9: addr=0x1d82000, size=4096 bytes */ |
36 | 0x1e00, /* win 10: addr=0x1e00000, size=4096 bytes */ |
37 | 0x1e01, /* win 11: addr=0x1e01000, size=4096 bytes */ |
38 | 0x1e80, /* win 12: addr=0x1e80000, size=4096 bytes */ |
39 | 0x1f00, /* win 13: addr=0x1f00000, size=4096 bytes */ |
40 | 0x1c08, /* win 14: addr=0x1c08000, size=4096 bytes */ |
41 | 0, |
42 | 0, |
43 | 0, |
44 | 0, |
45 | }; |
46 | |
47 | /* IRO Array */ |
48 | static const u32 iro_arr[] = { |
49 | 0x00000000, 0x00000000, 0x00080000, |
50 | 0x00004478, 0x00000008, 0x00080000, |
51 | 0x00003288, 0x00000088, 0x00880000, |
52 | 0x000058a8, 0x00000020, 0x00200000, |
53 | 0x00003188, 0x00000008, 0x00080000, |
54 | 0x00000b00, 0x00000008, 0x00040000, |
55 | 0x00000a80, 0x00000008, 0x00040000, |
56 | 0x00000000, 0x00000008, 0x00020000, |
57 | 0x00000080, 0x00000008, 0x00040000, |
58 | 0x00000084, 0x00000008, 0x00020000, |
59 | 0x00005798, 0x00000004, 0x00040000, |
60 | 0x00004e50, 0x00000000, 0x00780000, |
61 | 0x00003e40, 0x00000000, 0x00780000, |
62 | 0x00004500, 0x00000000, 0x00780000, |
63 | 0x00003210, 0x00000000, 0x00780000, |
64 | 0x00003b50, 0x00000000, 0x00780000, |
65 | 0x00007f58, 0x00000000, 0x00780000, |
66 | 0x00005fd8, 0x00000000, 0x00080000, |
67 | 0x00007100, 0x00000000, 0x00080000, |
68 | 0x0000af20, 0x00000000, 0x00080000, |
69 | 0x00004398, 0x00000000, 0x00080000, |
70 | 0x0000a5a0, 0x00000000, 0x00080000, |
71 | 0x0000bde8, 0x00000000, 0x00080000, |
72 | 0x00000020, 0x00000004, 0x00040000, |
73 | 0x00005688, 0x00000010, 0x00100000, |
74 | 0x0000c210, 0x00000030, 0x00300000, |
75 | 0x0000b108, 0x00000038, 0x00380000, |
76 | 0x00003d20, 0x00000080, 0x00400000, |
77 | 0x0000bf60, 0x00000000, 0x00040000, |
78 | 0x00004560, 0x00040080, 0x00040000, |
79 | 0x000001f8, 0x00000004, 0x00040000, |
80 | 0x00003d60, 0x00000080, 0x00200000, |
81 | 0x00008960, 0x00000040, 0x00300000, |
82 | 0x0000e840, 0x00000060, 0x00600000, |
83 | 0x00004698, 0x00000080, 0x00380000, |
84 | 0x000107b8, 0x000000c0, 0x00c00000, |
85 | 0x000001f8, 0x00000002, 0x00020000, |
86 | 0x0000a260, 0x00000000, 0x01080000, |
87 | 0x0000a368, 0x00000008, 0x00080000, |
88 | 0x000001c0, 0x00000008, 0x00080000, |
89 | 0x000001f8, 0x00000008, 0x00080000, |
90 | 0x00000ac0, 0x00000008, 0x00080000, |
91 | 0x00002578, 0x00000008, 0x00080000, |
92 | 0x000024f8, 0x00000008, 0x00080000, |
93 | 0x00000280, 0x00000008, 0x00080000, |
94 | 0x00000680, 0x00080018, 0x00080000, |
95 | 0x00000b78, 0x00080018, 0x00020000, |
96 | 0x0000c600, 0x00000058, 0x003c0000, |
97 | 0x00012038, 0x00000020, 0x00100000, |
98 | 0x00011b00, 0x00000048, 0x00180000, |
99 | 0x00009650, 0x00000050, 0x00200000, |
100 | 0x00008b10, 0x00000040, 0x00280000, |
101 | 0x000116c0, 0x00000018, 0x00100000, |
102 | 0x0000c808, 0x00000048, 0x00380000, |
103 | 0x00011790, 0x00000020, 0x00200000, |
104 | 0x000046d0, 0x00000080, 0x00100000, |
105 | 0x00003618, 0x00000010, 0x00100000, |
106 | 0x0000a9e8, 0x00000008, 0x00010000, |
107 | 0x000097a0, 0x00000008, 0x00010000, |
108 | 0x00011a10, 0x00000008, 0x00010000, |
109 | 0x0000e9f8, 0x00000008, 0x00010000, |
110 | 0x00012648, 0x00000008, 0x00010000, |
111 | 0x000121c8, 0x00000008, 0x00010000, |
112 | 0x0000af08, 0x00000030, 0x00100000, |
113 | 0x0000d748, 0x00000028, 0x00280000, |
114 | 0x00009e68, 0x00000018, 0x00180000, |
115 | 0x00009fe8, 0x00000008, 0x00080000, |
116 | 0x00013ea8, 0x00000008, 0x00080000, |
117 | 0x00012f18, 0x00000018, 0x00180000, |
118 | 0x0000dfe8, 0x00500288, 0x00100000, |
119 | 0x000131a0, 0x00000138, 0x00280000, |
120 | }; |
121 | |
122 | void qed_init_iro_array(struct qed_dev *cdev) |
123 | { |
124 | cdev->iro_arr = iro_arr + E4_IRO_ARR_OFFSET; |
125 | } |
126 | |
127 | void qed_init_store_rt_reg(struct qed_hwfn *p_hwfn, u32 rt_offset, u32 val) |
128 | { |
129 | if (rt_offset >= RUNTIME_ARRAY_SIZE) { |
130 | DP_ERR(p_hwfn, |
131 | "Avoid storing %u in rt_data at index %u!\n" , |
132 | val, rt_offset); |
133 | return; |
134 | } |
135 | |
136 | p_hwfn->rt_data.init_val[rt_offset] = val; |
137 | p_hwfn->rt_data.b_valid[rt_offset] = true; |
138 | } |
139 | |
140 | void qed_init_store_rt_agg(struct qed_hwfn *p_hwfn, |
141 | u32 rt_offset, u32 *p_val, size_t size) |
142 | { |
143 | size_t i; |
144 | |
145 | if ((rt_offset + size - 1) >= RUNTIME_ARRAY_SIZE) { |
146 | DP_ERR(p_hwfn, |
147 | "Avoid storing values in rt_data at indices %u-%u!\n" , |
148 | rt_offset, |
149 | (u32)(rt_offset + size - 1)); |
150 | return; |
151 | } |
152 | |
153 | for (i = 0; i < size / sizeof(u32); i++) { |
154 | p_hwfn->rt_data.init_val[rt_offset + i] = p_val[i]; |
155 | p_hwfn->rt_data.b_valid[rt_offset + i] = true; |
156 | } |
157 | } |
158 | |
159 | static int qed_init_rt(struct qed_hwfn *p_hwfn, |
160 | struct qed_ptt *p_ptt, |
161 | u32 addr, u16 rt_offset, u16 size, bool b_must_dmae) |
162 | { |
163 | u32 *p_init_val = &p_hwfn->rt_data.init_val[rt_offset]; |
164 | bool *p_valid = &p_hwfn->rt_data.b_valid[rt_offset]; |
165 | u16 i, j, segment; |
166 | int rc = 0; |
167 | |
168 | /* Since not all RT entries are initialized, go over the RT and |
169 | * for each segment of initialized values use DMA. |
170 | */ |
171 | for (i = 0; i < size; i++) { |
172 | if (!p_valid[i]) |
173 | continue; |
174 | |
175 | /* In case there isn't any wide-bus configuration here, |
176 | * simply write the data instead of using dmae. |
177 | */ |
178 | if (!b_must_dmae) { |
179 | qed_wr(p_hwfn, p_ptt, hw_addr: addr + (i << 2), val: p_init_val[i]); |
180 | p_valid[i] = false; |
181 | continue; |
182 | } |
183 | |
184 | /* Start of a new segment */ |
185 | for (segment = 1; i + segment < size; segment++) |
186 | if (!p_valid[i + segment]) |
187 | break; |
188 | |
189 | rc = qed_dmae_host2grc(p_hwfn, p_ptt, |
190 | source_addr: (uintptr_t)(p_init_val + i), |
191 | grc_addr: addr + (i << 2), size_in_dwords: segment, NULL); |
192 | if (rc) |
193 | return rc; |
194 | |
195 | /* invalidate after writing */ |
196 | for (j = i; j < (u32)(i + segment); j++) |
197 | p_valid[j] = false; |
198 | |
199 | /* Jump over the entire segment, including invalid entry */ |
200 | i += segment; |
201 | } |
202 | |
203 | return rc; |
204 | } |
205 | |
206 | int qed_init_alloc(struct qed_hwfn *p_hwfn) |
207 | { |
208 | struct qed_rt_data *rt_data = &p_hwfn->rt_data; |
209 | |
210 | if (IS_VF(p_hwfn->cdev)) |
211 | return 0; |
212 | |
213 | rt_data->b_valid = kcalloc(RUNTIME_ARRAY_SIZE, size: sizeof(bool), |
214 | GFP_KERNEL); |
215 | if (!rt_data->b_valid) |
216 | return -ENOMEM; |
217 | |
218 | rt_data->init_val = kcalloc(RUNTIME_ARRAY_SIZE, size: sizeof(u32), |
219 | GFP_KERNEL); |
220 | if (!rt_data->init_val) { |
221 | kfree(objp: rt_data->b_valid); |
222 | rt_data->b_valid = NULL; |
223 | return -ENOMEM; |
224 | } |
225 | |
226 | return 0; |
227 | } |
228 | |
229 | void qed_init_free(struct qed_hwfn *p_hwfn) |
230 | { |
231 | kfree(objp: p_hwfn->rt_data.init_val); |
232 | p_hwfn->rt_data.init_val = NULL; |
233 | kfree(objp: p_hwfn->rt_data.b_valid); |
234 | p_hwfn->rt_data.b_valid = NULL; |
235 | } |
236 | |
237 | static int qed_init_array_dmae(struct qed_hwfn *p_hwfn, |
238 | struct qed_ptt *p_ptt, |
239 | u32 addr, |
240 | u32 dmae_data_offset, |
241 | u32 size, |
242 | const u32 *buf, |
243 | bool b_must_dmae, |
244 | bool b_can_dmae) |
245 | { |
246 | int rc = 0; |
247 | |
248 | /* Perform DMAE only for lengthy enough sections or for wide-bus */ |
249 | if (!b_can_dmae || (!b_must_dmae && (size < 16))) { |
250 | const u32 *data = buf + dmae_data_offset; |
251 | u32 i; |
252 | |
253 | for (i = 0; i < size; i++) |
254 | qed_wr(p_hwfn, p_ptt, hw_addr: addr + (i << 2), val: data[i]); |
255 | } else { |
256 | rc = qed_dmae_host2grc(p_hwfn, p_ptt, |
257 | source_addr: (uintptr_t)(buf + dmae_data_offset), |
258 | grc_addr: addr, size_in_dwords: size, NULL); |
259 | } |
260 | |
261 | return rc; |
262 | } |
263 | |
264 | static int qed_init_fill_dmae(struct qed_hwfn *p_hwfn, |
265 | struct qed_ptt *p_ptt, |
266 | u32 addr, u32 fill_count) |
267 | { |
268 | static u32 zero_buffer[DMAE_MAX_RW_SIZE]; |
269 | struct qed_dmae_params params = {}; |
270 | |
271 | memset(zero_buffer, 0, sizeof(u32) * DMAE_MAX_RW_SIZE); |
272 | |
273 | /* invoke the DMAE virtual/physical buffer API with |
274 | * 1. DMAE init channel |
275 | * 2. addr, |
276 | * 3. p_hwfb->temp_data, |
277 | * 4. fill_count |
278 | */ |
279 | SET_FIELD(params.flags, QED_DMAE_PARAMS_RW_REPL_SRC, 0x1); |
280 | return qed_dmae_host2grc(p_hwfn, p_ptt, |
281 | source_addr: (uintptr_t)(&zero_buffer[0]), |
282 | grc_addr: addr, size_in_dwords: fill_count, p_params: ¶ms); |
283 | } |
284 | |
285 | static void qed_init_fill(struct qed_hwfn *p_hwfn, |
286 | struct qed_ptt *p_ptt, |
287 | u32 addr, u32 fill, u32 fill_count) |
288 | { |
289 | u32 i; |
290 | |
291 | for (i = 0; i < fill_count; i++, addr += sizeof(u32)) |
292 | qed_wr(p_hwfn, p_ptt, hw_addr: addr, val: fill); |
293 | } |
294 | |
295 | static int qed_init_cmd_array(struct qed_hwfn *p_hwfn, |
296 | struct qed_ptt *p_ptt, |
297 | struct init_write_op *cmd, |
298 | bool b_must_dmae, bool b_can_dmae) |
299 | { |
300 | u32 dmae_array_offset = le32_to_cpu(cmd->args.array_offset); |
301 | u32 data = le32_to_cpu(cmd->data); |
302 | u32 addr = GET_FIELD(data, INIT_WRITE_OP_ADDRESS) << 2; |
303 | |
304 | u32 offset, output_len, input_len, max_size; |
305 | struct qed_dev *cdev = p_hwfn->cdev; |
306 | union init_array_hdr *hdr; |
307 | const u32 *array_data; |
308 | int rc = 0; |
309 | u32 size; |
310 | |
311 | array_data = cdev->fw_data->arr_data; |
312 | |
313 | hdr = (union init_array_hdr *)(array_data + dmae_array_offset); |
314 | data = le32_to_cpu(hdr->raw.data); |
315 | switch (GET_FIELD(data, INIT_ARRAY_RAW_HDR_TYPE)) { |
316 | case INIT_ARR_ZIPPED: |
317 | offset = dmae_array_offset + 1; |
318 | input_len = GET_FIELD(data, |
319 | INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE); |
320 | max_size = MAX_ZIPPED_SIZE * 4; |
321 | memset(p_hwfn->unzip_buf, 0, max_size); |
322 | |
323 | output_len = qed_unzip_data(p_hwfn, input_len, |
324 | input_buf: (u8 *)&array_data[offset], |
325 | max_size, unzip_buf: (u8 *)p_hwfn->unzip_buf); |
326 | if (output_len) { |
327 | rc = qed_init_array_dmae(p_hwfn, p_ptt, addr, dmae_data_offset: 0, |
328 | size: output_len, |
329 | buf: p_hwfn->unzip_buf, |
330 | b_must_dmae, b_can_dmae); |
331 | } else { |
332 | DP_NOTICE(p_hwfn, "Failed to unzip dmae data\n" ); |
333 | rc = -EINVAL; |
334 | } |
335 | break; |
336 | case INIT_ARR_PATTERN: |
337 | { |
338 | u32 repeats = GET_FIELD(data, |
339 | INIT_ARRAY_PATTERN_HDR_REPETITIONS); |
340 | u32 i; |
341 | |
342 | size = GET_FIELD(data, INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE); |
343 | |
344 | for (i = 0; i < repeats; i++, addr += size << 2) { |
345 | rc = qed_init_array_dmae(p_hwfn, p_ptt, addr, |
346 | dmae_data_offset: dmae_array_offset + 1, |
347 | size, buf: array_data, |
348 | b_must_dmae, b_can_dmae); |
349 | if (rc) |
350 | break; |
351 | } |
352 | break; |
353 | } |
354 | case INIT_ARR_STANDARD: |
355 | size = GET_FIELD(data, INIT_ARRAY_STANDARD_HDR_SIZE); |
356 | rc = qed_init_array_dmae(p_hwfn, p_ptt, addr, |
357 | dmae_data_offset: dmae_array_offset + 1, |
358 | size, buf: array_data, |
359 | b_must_dmae, b_can_dmae); |
360 | break; |
361 | } |
362 | |
363 | return rc; |
364 | } |
365 | |
366 | /* init_ops write command */ |
367 | static int qed_init_cmd_wr(struct qed_hwfn *p_hwfn, |
368 | struct qed_ptt *p_ptt, |
369 | struct init_write_op *p_cmd, bool b_can_dmae) |
370 | { |
371 | u32 data = le32_to_cpu(p_cmd->data); |
372 | bool b_must_dmae = GET_FIELD(data, INIT_WRITE_OP_WIDE_BUS); |
373 | u32 addr = GET_FIELD(data, INIT_WRITE_OP_ADDRESS) << 2; |
374 | union init_write_args *arg = &p_cmd->args; |
375 | int rc = 0; |
376 | |
377 | /* Sanitize */ |
378 | if (b_must_dmae && !b_can_dmae) { |
379 | DP_NOTICE(p_hwfn, |
380 | "Need to write to %08x for Wide-bus but DMAE isn't allowed\n" , |
381 | addr); |
382 | return -EINVAL; |
383 | } |
384 | |
385 | switch (GET_FIELD(data, INIT_WRITE_OP_SOURCE)) { |
386 | case INIT_SRC_INLINE: |
387 | data = le32_to_cpu(p_cmd->args.inline_val); |
388 | qed_wr(p_hwfn, p_ptt, hw_addr: addr, val: data); |
389 | break; |
390 | case INIT_SRC_ZEROS: |
391 | data = le32_to_cpu(p_cmd->args.zeros_count); |
392 | if (b_must_dmae || (b_can_dmae && (data >= 64))) |
393 | rc = qed_init_fill_dmae(p_hwfn, p_ptt, addr, fill_count: data); |
394 | else |
395 | qed_init_fill(p_hwfn, p_ptt, addr, fill: 0, fill_count: data); |
396 | break; |
397 | case INIT_SRC_ARRAY: |
398 | rc = qed_init_cmd_array(p_hwfn, p_ptt, cmd: p_cmd, |
399 | b_must_dmae, b_can_dmae); |
400 | break; |
401 | case INIT_SRC_RUNTIME: |
402 | qed_init_rt(p_hwfn, p_ptt, addr, |
403 | le16_to_cpu(arg->runtime.offset), |
404 | le16_to_cpu(arg->runtime.size), |
405 | b_must_dmae); |
406 | break; |
407 | } |
408 | |
409 | return rc; |
410 | } |
411 | |
412 | static inline bool comp_eq(u32 val, u32 expected_val) |
413 | { |
414 | return val == expected_val; |
415 | } |
416 | |
417 | static inline bool comp_and(u32 val, u32 expected_val) |
418 | { |
419 | return (val & expected_val) == expected_val; |
420 | } |
421 | |
422 | static inline bool comp_or(u32 val, u32 expected_val) |
423 | { |
424 | return (val | expected_val) > 0; |
425 | } |
426 | |
427 | /* init_ops read/poll commands */ |
428 | static void qed_init_cmd_rd(struct qed_hwfn *p_hwfn, |
429 | struct qed_ptt *p_ptt, struct init_read_op *cmd) |
430 | { |
431 | bool (*comp_check)(u32 val, u32 expected_val); |
432 | u32 delay = QED_INIT_POLL_PERIOD_US, val; |
433 | u32 data, addr, poll; |
434 | int i; |
435 | |
436 | data = le32_to_cpu(cmd->op_data); |
437 | addr = GET_FIELD(data, INIT_READ_OP_ADDRESS) << 2; |
438 | poll = GET_FIELD(data, INIT_READ_OP_POLL_TYPE); |
439 | |
440 | val = qed_rd(p_hwfn, p_ptt, hw_addr: addr); |
441 | |
442 | if (poll == INIT_POLL_NONE) |
443 | return; |
444 | |
445 | switch (poll) { |
446 | case INIT_POLL_EQ: |
447 | comp_check = comp_eq; |
448 | break; |
449 | case INIT_POLL_OR: |
450 | comp_check = comp_or; |
451 | break; |
452 | case INIT_POLL_AND: |
453 | comp_check = comp_and; |
454 | break; |
455 | default: |
456 | DP_ERR(p_hwfn, "Invalid poll comparison type %08x\n" , |
457 | cmd->op_data); |
458 | return; |
459 | } |
460 | |
461 | data = le32_to_cpu(cmd->expected_val); |
462 | for (i = 0; |
463 | i < QED_INIT_MAX_POLL_COUNT && !comp_check(val, data); |
464 | i++) { |
465 | udelay(delay); |
466 | val = qed_rd(p_hwfn, p_ptt, hw_addr: addr); |
467 | } |
468 | |
469 | if (i == QED_INIT_MAX_POLL_COUNT) { |
470 | DP_ERR(p_hwfn, |
471 | "Timeout when polling reg: 0x%08x [ Waiting-for: %08x Got: %08x (comparison %08x)]\n" , |
472 | addr, le32_to_cpu(cmd->expected_val), |
473 | val, le32_to_cpu(cmd->op_data)); |
474 | } |
475 | } |
476 | |
477 | /* init_ops callbacks entry point */ |
478 | static int qed_init_cmd_cb(struct qed_hwfn *p_hwfn, |
479 | struct qed_ptt *p_ptt, |
480 | struct init_callback_op *p_cmd) |
481 | { |
482 | int rc; |
483 | |
484 | switch (p_cmd->callback_id) { |
485 | case DMAE_READY_CB: |
486 | rc = qed_dmae_sanity(p_hwfn, p_ptt, phase: "engine_phase" ); |
487 | break; |
488 | default: |
489 | DP_NOTICE(p_hwfn, "Unexpected init op callback ID %d\n" , |
490 | p_cmd->callback_id); |
491 | return -EINVAL; |
492 | } |
493 | |
494 | return rc; |
495 | } |
496 | |
497 | static u8 qed_init_cmd_mode_match(struct qed_hwfn *p_hwfn, |
498 | u16 *p_offset, int modes) |
499 | { |
500 | struct qed_dev *cdev = p_hwfn->cdev; |
501 | const u8 *modes_tree_buf; |
502 | u8 arg1, arg2, tree_val; |
503 | |
504 | modes_tree_buf = cdev->fw_data->modes_tree_buf; |
505 | tree_val = modes_tree_buf[(*p_offset)++]; |
506 | switch (tree_val) { |
507 | case INIT_MODE_OP_NOT: |
508 | return qed_init_cmd_mode_match(p_hwfn, p_offset, modes) ^ 1; |
509 | case INIT_MODE_OP_OR: |
510 | arg1 = qed_init_cmd_mode_match(p_hwfn, p_offset, modes); |
511 | arg2 = qed_init_cmd_mode_match(p_hwfn, p_offset, modes); |
512 | return arg1 | arg2; |
513 | case INIT_MODE_OP_AND: |
514 | arg1 = qed_init_cmd_mode_match(p_hwfn, p_offset, modes); |
515 | arg2 = qed_init_cmd_mode_match(p_hwfn, p_offset, modes); |
516 | return arg1 & arg2; |
517 | default: |
518 | tree_val -= MAX_INIT_MODE_OPS; |
519 | return (modes & BIT(tree_val)) ? 1 : 0; |
520 | } |
521 | } |
522 | |
523 | static u32 qed_init_cmd_mode(struct qed_hwfn *p_hwfn, |
524 | struct init_if_mode_op *p_cmd, int modes) |
525 | { |
526 | u16 offset = le16_to_cpu(p_cmd->modes_buf_offset); |
527 | |
528 | if (qed_init_cmd_mode_match(p_hwfn, p_offset: &offset, modes)) |
529 | return 0; |
530 | else |
531 | return GET_FIELD(le32_to_cpu(p_cmd->op_data), |
532 | INIT_IF_MODE_OP_CMD_OFFSET); |
533 | } |
534 | |
535 | static u32 qed_init_cmd_phase(struct init_if_phase_op *p_cmd, |
536 | u32 phase, u32 phase_id) |
537 | { |
538 | u32 data = le32_to_cpu(p_cmd->phase_data); |
539 | u32 op_data = le32_to_cpu(p_cmd->op_data); |
540 | |
541 | if (!(GET_FIELD(data, INIT_IF_PHASE_OP_PHASE) == phase && |
542 | (GET_FIELD(data, INIT_IF_PHASE_OP_PHASE_ID) == ANY_PHASE_ID || |
543 | GET_FIELD(data, INIT_IF_PHASE_OP_PHASE_ID) == phase_id))) |
544 | return GET_FIELD(op_data, INIT_IF_PHASE_OP_CMD_OFFSET); |
545 | else |
546 | return 0; |
547 | } |
548 | |
549 | int qed_init_run(struct qed_hwfn *p_hwfn, |
550 | struct qed_ptt *p_ptt, int phase, int phase_id, int modes) |
551 | { |
552 | bool b_dmae = (phase != PHASE_ENGINE); |
553 | struct qed_dev *cdev = p_hwfn->cdev; |
554 | u32 cmd_num, num_init_ops; |
555 | union init_op *init_ops; |
556 | int rc = 0; |
557 | |
558 | num_init_ops = cdev->fw_data->init_ops_size; |
559 | init_ops = cdev->fw_data->init_ops; |
560 | |
561 | p_hwfn->unzip_buf = kzalloc(MAX_ZIPPED_SIZE * 4, GFP_ATOMIC); |
562 | if (!p_hwfn->unzip_buf) |
563 | return -ENOMEM; |
564 | |
565 | for (cmd_num = 0; cmd_num < num_init_ops; cmd_num++) { |
566 | union init_op *cmd = &init_ops[cmd_num]; |
567 | u32 data = le32_to_cpu(cmd->raw.op_data); |
568 | |
569 | switch (GET_FIELD(data, INIT_CALLBACK_OP_OP)) { |
570 | case INIT_OP_WRITE: |
571 | rc = qed_init_cmd_wr(p_hwfn, p_ptt, p_cmd: &cmd->write, |
572 | b_can_dmae: b_dmae); |
573 | break; |
574 | case INIT_OP_READ: |
575 | qed_init_cmd_rd(p_hwfn, p_ptt, cmd: &cmd->read); |
576 | break; |
577 | case INIT_OP_IF_MODE: |
578 | cmd_num += qed_init_cmd_mode(p_hwfn, p_cmd: &cmd->if_mode, |
579 | modes); |
580 | break; |
581 | case INIT_OP_IF_PHASE: |
582 | cmd_num += qed_init_cmd_phase(p_cmd: &cmd->if_phase, |
583 | phase, phase_id); |
584 | break; |
585 | case INIT_OP_DELAY: |
586 | /* qed_init_run is always invoked from |
587 | * sleep-able context |
588 | */ |
589 | udelay(le32_to_cpu(cmd->delay.delay)); |
590 | break; |
591 | |
592 | case INIT_OP_CALLBACK: |
593 | rc = qed_init_cmd_cb(p_hwfn, p_ptt, p_cmd: &cmd->callback); |
594 | if (phase == PHASE_ENGINE && |
595 | cmd->callback.callback_id == DMAE_READY_CB) |
596 | b_dmae = true; |
597 | break; |
598 | } |
599 | |
600 | if (rc) |
601 | break; |
602 | } |
603 | |
604 | kfree(objp: p_hwfn->unzip_buf); |
605 | p_hwfn->unzip_buf = NULL; |
606 | return rc; |
607 | } |
608 | |
609 | void qed_gtt_init(struct qed_hwfn *p_hwfn) |
610 | { |
611 | u32 gtt_base; |
612 | u32 i; |
613 | |
614 | /* Set the global windows */ |
615 | gtt_base = PXP_PF_WINDOW_ADMIN_START + PXP_PF_WINDOW_ADMIN_GLOBAL_START; |
616 | |
617 | for (i = 0; i < ARRAY_SIZE(pxp_global_win); i++) |
618 | if (pxp_global_win[i]) |
619 | REG_WR(p_hwfn, gtt_base + i * PXP_GLOBAL_ENTRY_SIZE, |
620 | pxp_global_win[i]); |
621 | } |
622 | |
623 | int qed_init_fw_data(struct qed_dev *cdev, const u8 *data) |
624 | { |
625 | struct qed_fw_data *fw = cdev->fw_data; |
626 | struct bin_buffer_hdr *buf_hdr; |
627 | u32 offset, len; |
628 | |
629 | if (!data) { |
630 | DP_NOTICE(cdev, "Invalid fw data\n" ); |
631 | return -EINVAL; |
632 | } |
633 | |
634 | /* First Dword contains metadata and should be skipped */ |
635 | buf_hdr = (struct bin_buffer_hdr *)data; |
636 | |
637 | offset = buf_hdr[BIN_BUF_INIT_FW_VER_INFO].offset; |
638 | fw->fw_ver_info = (struct fw_ver_info *)(data + offset); |
639 | |
640 | offset = buf_hdr[BIN_BUF_INIT_CMD].offset; |
641 | fw->init_ops = (union init_op *)(data + offset); |
642 | |
643 | offset = buf_hdr[BIN_BUF_INIT_VAL].offset; |
644 | fw->arr_data = (u32 *)(data + offset); |
645 | |
646 | offset = buf_hdr[BIN_BUF_INIT_MODE_TREE].offset; |
647 | fw->modes_tree_buf = (u8 *)(data + offset); |
648 | len = buf_hdr[BIN_BUF_INIT_CMD].length; |
649 | fw->init_ops_size = len / sizeof(struct init_raw_op); |
650 | |
651 | offset = buf_hdr[BIN_BUF_INIT_OVERLAYS].offset; |
652 | fw->fw_overlays = (u32 *)(data + offset); |
653 | len = buf_hdr[BIN_BUF_INIT_OVERLAYS].length; |
654 | fw->fw_overlays_len = len; |
655 | |
656 | return 0; |
657 | } |
658 | |