Loading...
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
25static 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 */
48static 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
122void qed_init_iro_array(struct qed_dev *cdev)
123{
124 cdev->iro_arr = iro_arr + E4_IRO_ARR_OFFSET;
125}
126
127void 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
140void 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
159static 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, addr + (i << 2), 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 (uintptr_t)(p_init_val + i),
191 addr + (i << 2), 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
206int 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, sizeof(bool),
214 GFP_KERNEL);
215 if (!rt_data->b_valid)
216 return -ENOMEM;
217
218 rt_data->init_val = kcalloc(RUNTIME_ARRAY_SIZE, sizeof(u32),
219 GFP_KERNEL);
220 if (!rt_data->init_val) {
221 kfree(rt_data->b_valid);
222 rt_data->b_valid = NULL;
223 return -ENOMEM;
224 }
225
226 return 0;
227}
228
229void qed_init_free(struct qed_hwfn *p_hwfn)
230{
231 kfree(p_hwfn->rt_data.init_val);
232 p_hwfn->rt_data.init_val = NULL;
233 kfree(p_hwfn->rt_data.b_valid);
234 p_hwfn->rt_data.b_valid = NULL;
235}
236
237static 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, addr + (i << 2), data[i]);
255 } else {
256 rc = qed_dmae_host2grc(p_hwfn, p_ptt,
257 (uintptr_t)(buf + dmae_data_offset),
258 addr, size, NULL);
259 }
260
261 return rc;
262}
263
264static 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 (uintptr_t)(&zero_buffer[0]),
282 addr, fill_count, ¶ms);
283}
284
285static 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, addr, fill);
293}
294
295static 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 (u8 *)&array_data[offset],
325 max_size, (u8 *)p_hwfn->unzip_buf);
326 if (output_len) {
327 rc = qed_init_array_dmae(p_hwfn, p_ptt, addr, 0,
328 output_len,
329 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_array_offset + 1,
347 size, 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_array_offset + 1,
358 size, array_data,
359 b_must_dmae, b_can_dmae);
360 break;
361 }
362
363 return rc;
364}
365
366/* init_ops write command */
367static 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, addr, 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, data);
394 else
395 qed_init_fill(p_hwfn, p_ptt, addr, 0, data);
396 break;
397 case INIT_SRC_ARRAY:
398 rc = qed_init_cmd_array(p_hwfn, p_ptt, 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
412static inline bool comp_eq(u32 val, u32 expected_val)
413{
414 return val == expected_val;
415}
416
417static inline bool comp_and(u32 val, u32 expected_val)
418{
419 return (val & expected_val) == expected_val;
420}
421
422static inline bool comp_or(u32 val, u32 expected_val)
423{
424 return (val | expected_val) > 0;
425}
426
427/* init_ops read/poll commands */
428static 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, 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, 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 */
478static 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, "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
497static 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
523static 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, &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
535static 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
549int 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, &cmd->write,
572 b_dmae);
573 break;
574 case INIT_OP_READ:
575 qed_init_cmd_rd(p_hwfn, p_ptt, &cmd->read);
576 break;
577 case INIT_OP_IF_MODE:
578 cmd_num += qed_init_cmd_mode(p_hwfn, &cmd->if_mode,
579 modes);
580 break;
581 case INIT_OP_IF_PHASE:
582 cmd_num += qed_init_cmd_phase(&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, &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(p_hwfn->unzip_buf);
605 p_hwfn->unzip_buf = NULL;
606 return rc;
607}
608
609void 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
623int 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}
1/* QLogic qed NIC Driver
2 * Copyright (c) 2015-2017 QLogic Corporation
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and /or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33#include <linux/types.h>
34#include <linux/io.h>
35#include <linux/delay.h>
36#include <linux/errno.h>
37#include <linux/kernel.h>
38#include <linux/slab.h>
39#include <linux/string.h>
40#include "qed.h"
41#include "qed_hsi.h"
42#include "qed_hw.h"
43#include "qed_init_ops.h"
44#include "qed_reg_addr.h"
45#include "qed_sriov.h"
46
47#define QED_INIT_MAX_POLL_COUNT 100
48#define QED_INIT_POLL_PERIOD_US 500
49
50static u32 pxp_global_win[] = {
51 0,
52 0,
53 0x1c02, /* win 2: addr=0x1c02000, size=4096 bytes */
54 0x1c80, /* win 3: addr=0x1c80000, size=4096 bytes */
55 0x1d00, /* win 4: addr=0x1d00000, size=4096 bytes */
56 0x1d01, /* win 5: addr=0x1d01000, size=4096 bytes */
57 0x1d80, /* win 6: addr=0x1d80000, size=4096 bytes */
58 0x1d81, /* win 7: addr=0x1d81000, size=4096 bytes */
59 0x1d82, /* win 8: addr=0x1d82000, size=4096 bytes */
60 0x1e00, /* win 9: addr=0x1e00000, size=4096 bytes */
61 0x1e80, /* win 10: addr=0x1e80000, size=4096 bytes */
62 0x1f00, /* win 11: addr=0x1f00000, size=4096 bytes */
63 0,
64 0,
65 0,
66 0,
67 0,
68 0,
69 0,
70};
71
72void qed_init_iro_array(struct qed_dev *cdev)
73{
74 cdev->iro_arr = iro_arr;
75}
76
77/* Runtime configuration helpers */
78void qed_init_clear_rt_data(struct qed_hwfn *p_hwfn)
79{
80 int i;
81
82 for (i = 0; i < RUNTIME_ARRAY_SIZE; i++)
83 p_hwfn->rt_data.b_valid[i] = false;
84}
85
86void qed_init_store_rt_reg(struct qed_hwfn *p_hwfn, u32 rt_offset, u32 val)
87{
88 p_hwfn->rt_data.init_val[rt_offset] = val;
89 p_hwfn->rt_data.b_valid[rt_offset] = true;
90}
91
92void qed_init_store_rt_agg(struct qed_hwfn *p_hwfn,
93 u32 rt_offset, u32 *p_val, size_t size)
94{
95 size_t i;
96
97 for (i = 0; i < size / sizeof(u32); i++) {
98 p_hwfn->rt_data.init_val[rt_offset + i] = p_val[i];
99 p_hwfn->rt_data.b_valid[rt_offset + i] = true;
100 }
101}
102
103static int qed_init_rt(struct qed_hwfn *p_hwfn,
104 struct qed_ptt *p_ptt,
105 u32 addr, u16 rt_offset, u16 size, bool b_must_dmae)
106{
107 u32 *p_init_val = &p_hwfn->rt_data.init_val[rt_offset];
108 bool *p_valid = &p_hwfn->rt_data.b_valid[rt_offset];
109 u16 i, segment;
110 int rc = 0;
111
112 /* Since not all RT entries are initialized, go over the RT and
113 * for each segment of initialized values use DMA.
114 */
115 for (i = 0; i < size; i++) {
116 if (!p_valid[i])
117 continue;
118
119 /* In case there isn't any wide-bus configuration here,
120 * simply write the data instead of using dmae.
121 */
122 if (!b_must_dmae) {
123 qed_wr(p_hwfn, p_ptt, addr + (i << 2), p_init_val[i]);
124 continue;
125 }
126
127 /* Start of a new segment */
128 for (segment = 1; i + segment < size; segment++)
129 if (!p_valid[i + segment])
130 break;
131
132 rc = qed_dmae_host2grc(p_hwfn, p_ptt,
133 (uintptr_t)(p_init_val + i),
134 addr + (i << 2), segment, NULL);
135 if (rc)
136 return rc;
137
138 /* Jump over the entire segment, including invalid entry */
139 i += segment;
140 }
141
142 return rc;
143}
144
145int qed_init_alloc(struct qed_hwfn *p_hwfn)
146{
147 struct qed_rt_data *rt_data = &p_hwfn->rt_data;
148
149 if (IS_VF(p_hwfn->cdev))
150 return 0;
151
152 rt_data->b_valid = kcalloc(RUNTIME_ARRAY_SIZE, sizeof(bool),
153 GFP_KERNEL);
154 if (!rt_data->b_valid)
155 return -ENOMEM;
156
157 rt_data->init_val = kcalloc(RUNTIME_ARRAY_SIZE, sizeof(u32),
158 GFP_KERNEL);
159 if (!rt_data->init_val) {
160 kfree(rt_data->b_valid);
161 rt_data->b_valid = NULL;
162 return -ENOMEM;
163 }
164
165 return 0;
166}
167
168void qed_init_free(struct qed_hwfn *p_hwfn)
169{
170 kfree(p_hwfn->rt_data.init_val);
171 p_hwfn->rt_data.init_val = NULL;
172 kfree(p_hwfn->rt_data.b_valid);
173 p_hwfn->rt_data.b_valid = NULL;
174}
175
176static int qed_init_array_dmae(struct qed_hwfn *p_hwfn,
177 struct qed_ptt *p_ptt,
178 u32 addr,
179 u32 dmae_data_offset,
180 u32 size,
181 const u32 *buf,
182 bool b_must_dmae,
183 bool b_can_dmae)
184{
185 int rc = 0;
186
187 /* Perform DMAE only for lengthy enough sections or for wide-bus */
188 if (!b_can_dmae || (!b_must_dmae && (size < 16))) {
189 const u32 *data = buf + dmae_data_offset;
190 u32 i;
191
192 for (i = 0; i < size; i++)
193 qed_wr(p_hwfn, p_ptt, addr + (i << 2), data[i]);
194 } else {
195 rc = qed_dmae_host2grc(p_hwfn, p_ptt,
196 (uintptr_t)(buf + dmae_data_offset),
197 addr, size, NULL);
198 }
199
200 return rc;
201}
202
203static int qed_init_fill_dmae(struct qed_hwfn *p_hwfn,
204 struct qed_ptt *p_ptt,
205 u32 addr, u32 fill, u32 fill_count)
206{
207 static u32 zero_buffer[DMAE_MAX_RW_SIZE];
208 struct qed_dmae_params params = {};
209
210 memset(zero_buffer, 0, sizeof(u32) * DMAE_MAX_RW_SIZE);
211
212 /* invoke the DMAE virtual/physical buffer API with
213 * 1. DMAE init channel
214 * 2. addr,
215 * 3. p_hwfb->temp_data,
216 * 4. fill_count
217 */
218 params.flags = QED_DMAE_FLAG_RW_REPL_SRC;
219 return qed_dmae_host2grc(p_hwfn, p_ptt,
220 (uintptr_t)(&zero_buffer[0]),
221 addr, fill_count, ¶ms);
222}
223
224static void qed_init_fill(struct qed_hwfn *p_hwfn,
225 struct qed_ptt *p_ptt,
226 u32 addr, u32 fill, u32 fill_count)
227{
228 u32 i;
229
230 for (i = 0; i < fill_count; i++, addr += sizeof(u32))
231 qed_wr(p_hwfn, p_ptt, addr, fill);
232}
233
234static int qed_init_cmd_array(struct qed_hwfn *p_hwfn,
235 struct qed_ptt *p_ptt,
236 struct init_write_op *cmd,
237 bool b_must_dmae, bool b_can_dmae)
238{
239 u32 dmae_array_offset = le32_to_cpu(cmd->args.array_offset);
240 u32 data = le32_to_cpu(cmd->data);
241 u32 addr = GET_FIELD(data, INIT_WRITE_OP_ADDRESS) << 2;
242
243 u32 offset, output_len, input_len, max_size;
244 struct qed_dev *cdev = p_hwfn->cdev;
245 union init_array_hdr *hdr;
246 const u32 *array_data;
247 int rc = 0;
248 u32 size;
249
250 array_data = cdev->fw_data->arr_data;
251
252 hdr = (union init_array_hdr *)(array_data + dmae_array_offset);
253 data = le32_to_cpu(hdr->raw.data);
254 switch (GET_FIELD(data, INIT_ARRAY_RAW_HDR_TYPE)) {
255 case INIT_ARR_ZIPPED:
256 offset = dmae_array_offset + 1;
257 input_len = GET_FIELD(data,
258 INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE);
259 max_size = MAX_ZIPPED_SIZE * 4;
260 memset(p_hwfn->unzip_buf, 0, max_size);
261
262 output_len = qed_unzip_data(p_hwfn, input_len,
263 (u8 *)&array_data[offset],
264 max_size, (u8 *)p_hwfn->unzip_buf);
265 if (output_len) {
266 rc = qed_init_array_dmae(p_hwfn, p_ptt, addr, 0,
267 output_len,
268 p_hwfn->unzip_buf,
269 b_must_dmae, b_can_dmae);
270 } else {
271 DP_NOTICE(p_hwfn, "Failed to unzip dmae data\n");
272 rc = -EINVAL;
273 }
274 break;
275 case INIT_ARR_PATTERN:
276 {
277 u32 repeats = GET_FIELD(data,
278 INIT_ARRAY_PATTERN_HDR_REPETITIONS);
279 u32 i;
280
281 size = GET_FIELD(data, INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE);
282
283 for (i = 0; i < repeats; i++, addr += size << 2) {
284 rc = qed_init_array_dmae(p_hwfn, p_ptt, addr,
285 dmae_array_offset + 1,
286 size, array_data,
287 b_must_dmae, b_can_dmae);
288 if (rc)
289 break;
290 }
291 break;
292 }
293 case INIT_ARR_STANDARD:
294 size = GET_FIELD(data, INIT_ARRAY_STANDARD_HDR_SIZE);
295 rc = qed_init_array_dmae(p_hwfn, p_ptt, addr,
296 dmae_array_offset + 1,
297 size, array_data,
298 b_must_dmae, b_can_dmae);
299 break;
300 }
301
302 return rc;
303}
304
305/* init_ops write command */
306static int qed_init_cmd_wr(struct qed_hwfn *p_hwfn,
307 struct qed_ptt *p_ptt,
308 struct init_write_op *p_cmd, bool b_can_dmae)
309{
310 u32 data = le32_to_cpu(p_cmd->data);
311 bool b_must_dmae = GET_FIELD(data, INIT_WRITE_OP_WIDE_BUS);
312 u32 addr = GET_FIELD(data, INIT_WRITE_OP_ADDRESS) << 2;
313 union init_write_args *arg = &p_cmd->args;
314 int rc = 0;
315
316 /* Sanitize */
317 if (b_must_dmae && !b_can_dmae) {
318 DP_NOTICE(p_hwfn,
319 "Need to write to %08x for Wide-bus but DMAE isn't allowed\n",
320 addr);
321 return -EINVAL;
322 }
323
324 switch (GET_FIELD(data, INIT_WRITE_OP_SOURCE)) {
325 case INIT_SRC_INLINE:
326 data = le32_to_cpu(p_cmd->args.inline_val);
327 qed_wr(p_hwfn, p_ptt, addr, data);
328 break;
329 case INIT_SRC_ZEROS:
330 data = le32_to_cpu(p_cmd->args.zeros_count);
331 if (b_must_dmae || (b_can_dmae && (data >= 64)))
332 rc = qed_init_fill_dmae(p_hwfn, p_ptt, addr, 0, data);
333 else
334 qed_init_fill(p_hwfn, p_ptt, addr, 0, data);
335 break;
336 case INIT_SRC_ARRAY:
337 rc = qed_init_cmd_array(p_hwfn, p_ptt, p_cmd,
338 b_must_dmae, b_can_dmae);
339 break;
340 case INIT_SRC_RUNTIME:
341 qed_init_rt(p_hwfn, p_ptt, addr,
342 le16_to_cpu(arg->runtime.offset),
343 le16_to_cpu(arg->runtime.size),
344 b_must_dmae);
345 break;
346 }
347
348 return rc;
349}
350
351static inline bool comp_eq(u32 val, u32 expected_val)
352{
353 return val == expected_val;
354}
355
356static inline bool comp_and(u32 val, u32 expected_val)
357{
358 return (val & expected_val) == expected_val;
359}
360
361static inline bool comp_or(u32 val, u32 expected_val)
362{
363 return (val | expected_val) > 0;
364}
365
366/* init_ops read/poll commands */
367static void qed_init_cmd_rd(struct qed_hwfn *p_hwfn,
368 struct qed_ptt *p_ptt, struct init_read_op *cmd)
369{
370 bool (*comp_check)(u32 val, u32 expected_val);
371 u32 delay = QED_INIT_POLL_PERIOD_US, val;
372 u32 data, addr, poll;
373 int i;
374
375 data = le32_to_cpu(cmd->op_data);
376 addr = GET_FIELD(data, INIT_READ_OP_ADDRESS) << 2;
377 poll = GET_FIELD(data, INIT_READ_OP_POLL_TYPE);
378
379
380 val = qed_rd(p_hwfn, p_ptt, addr);
381
382 if (poll == INIT_POLL_NONE)
383 return;
384
385 switch (poll) {
386 case INIT_POLL_EQ:
387 comp_check = comp_eq;
388 break;
389 case INIT_POLL_OR:
390 comp_check = comp_or;
391 break;
392 case INIT_POLL_AND:
393 comp_check = comp_and;
394 break;
395 default:
396 DP_ERR(p_hwfn, "Invalid poll comparison type %08x\n",
397 cmd->op_data);
398 return;
399 }
400
401 data = le32_to_cpu(cmd->expected_val);
402 for (i = 0;
403 i < QED_INIT_MAX_POLL_COUNT && !comp_check(val, data);
404 i++) {
405 udelay(delay);
406 val = qed_rd(p_hwfn, p_ptt, addr);
407 }
408
409 if (i == QED_INIT_MAX_POLL_COUNT) {
410 DP_ERR(p_hwfn,
411 "Timeout when polling reg: 0x%08x [ Waiting-for: %08x Got: %08x (comparison %08x)]\n",
412 addr, le32_to_cpu(cmd->expected_val),
413 val, le32_to_cpu(cmd->op_data));
414 }
415}
416
417/* init_ops callbacks entry point */
418static int qed_init_cmd_cb(struct qed_hwfn *p_hwfn,
419 struct qed_ptt *p_ptt,
420 struct init_callback_op *p_cmd)
421{
422 int rc;
423
424 switch (p_cmd->callback_id) {
425 case DMAE_READY_CB:
426 rc = qed_dmae_sanity(p_hwfn, p_ptt, "engine_phase");
427 break;
428 default:
429 DP_NOTICE(p_hwfn, "Unexpected init op callback ID %d\n",
430 p_cmd->callback_id);
431 return -EINVAL;
432 }
433
434 return rc;
435}
436
437static u8 qed_init_cmd_mode_match(struct qed_hwfn *p_hwfn,
438 u16 *p_offset, int modes)
439{
440 struct qed_dev *cdev = p_hwfn->cdev;
441 const u8 *modes_tree_buf;
442 u8 arg1, arg2, tree_val;
443
444 modes_tree_buf = cdev->fw_data->modes_tree_buf;
445 tree_val = modes_tree_buf[(*p_offset)++];
446 switch (tree_val) {
447 case INIT_MODE_OP_NOT:
448 return qed_init_cmd_mode_match(p_hwfn, p_offset, modes) ^ 1;
449 case INIT_MODE_OP_OR:
450 arg1 = qed_init_cmd_mode_match(p_hwfn, p_offset, modes);
451 arg2 = qed_init_cmd_mode_match(p_hwfn, p_offset, modes);
452 return arg1 | arg2;
453 case INIT_MODE_OP_AND:
454 arg1 = qed_init_cmd_mode_match(p_hwfn, p_offset, modes);
455 arg2 = qed_init_cmd_mode_match(p_hwfn, p_offset, modes);
456 return arg1 & arg2;
457 default:
458 tree_val -= MAX_INIT_MODE_OPS;
459 return (modes & BIT(tree_val)) ? 1 : 0;
460 }
461}
462
463static u32 qed_init_cmd_mode(struct qed_hwfn *p_hwfn,
464 struct init_if_mode_op *p_cmd, int modes)
465{
466 u16 offset = le16_to_cpu(p_cmd->modes_buf_offset);
467
468 if (qed_init_cmd_mode_match(p_hwfn, &offset, modes))
469 return 0;
470 else
471 return GET_FIELD(le32_to_cpu(p_cmd->op_data),
472 INIT_IF_MODE_OP_CMD_OFFSET);
473}
474
475static u32 qed_init_cmd_phase(struct qed_hwfn *p_hwfn,
476 struct init_if_phase_op *p_cmd,
477 u32 phase, u32 phase_id)
478{
479 u32 data = le32_to_cpu(p_cmd->phase_data);
480 u32 op_data = le32_to_cpu(p_cmd->op_data);
481
482 if (!(GET_FIELD(data, INIT_IF_PHASE_OP_PHASE) == phase &&
483 (GET_FIELD(data, INIT_IF_PHASE_OP_PHASE_ID) == ANY_PHASE_ID ||
484 GET_FIELD(data, INIT_IF_PHASE_OP_PHASE_ID) == phase_id)))
485 return GET_FIELD(op_data, INIT_IF_PHASE_OP_CMD_OFFSET);
486 else
487 return 0;
488}
489
490int qed_init_run(struct qed_hwfn *p_hwfn,
491 struct qed_ptt *p_ptt, int phase, int phase_id, int modes)
492{
493 struct qed_dev *cdev = p_hwfn->cdev;
494 u32 cmd_num, num_init_ops;
495 union init_op *init_ops;
496 bool b_dmae = false;
497 int rc = 0;
498
499 num_init_ops = cdev->fw_data->init_ops_size;
500 init_ops = cdev->fw_data->init_ops;
501
502 p_hwfn->unzip_buf = kzalloc(MAX_ZIPPED_SIZE * 4, GFP_ATOMIC);
503 if (!p_hwfn->unzip_buf)
504 return -ENOMEM;
505
506 for (cmd_num = 0; cmd_num < num_init_ops; cmd_num++) {
507 union init_op *cmd = &init_ops[cmd_num];
508 u32 data = le32_to_cpu(cmd->raw.op_data);
509
510 switch (GET_FIELD(data, INIT_CALLBACK_OP_OP)) {
511 case INIT_OP_WRITE:
512 rc = qed_init_cmd_wr(p_hwfn, p_ptt, &cmd->write,
513 b_dmae);
514 break;
515 case INIT_OP_READ:
516 qed_init_cmd_rd(p_hwfn, p_ptt, &cmd->read);
517 break;
518 case INIT_OP_IF_MODE:
519 cmd_num += qed_init_cmd_mode(p_hwfn, &cmd->if_mode,
520 modes);
521 break;
522 case INIT_OP_IF_PHASE:
523 cmd_num += qed_init_cmd_phase(p_hwfn, &cmd->if_phase,
524 phase, phase_id);
525 b_dmae = GET_FIELD(data, INIT_IF_PHASE_OP_DMAE_ENABLE);
526 break;
527 case INIT_OP_DELAY:
528 /* qed_init_run is always invoked from
529 * sleep-able context
530 */
531 udelay(le32_to_cpu(cmd->delay.delay));
532 break;
533
534 case INIT_OP_CALLBACK:
535 rc = qed_init_cmd_cb(p_hwfn, p_ptt, &cmd->callback);
536 break;
537 }
538
539 if (rc)
540 break;
541 }
542
543 kfree(p_hwfn->unzip_buf);
544 p_hwfn->unzip_buf = NULL;
545 return rc;
546}
547
548void qed_gtt_init(struct qed_hwfn *p_hwfn)
549{
550 u32 gtt_base;
551 u32 i;
552
553 /* Set the global windows */
554 gtt_base = PXP_PF_WINDOW_ADMIN_START + PXP_PF_WINDOW_ADMIN_GLOBAL_START;
555
556 for (i = 0; i < ARRAY_SIZE(pxp_global_win); i++)
557 if (pxp_global_win[i])
558 REG_WR(p_hwfn, gtt_base + i * PXP_GLOBAL_ENTRY_SIZE,
559 pxp_global_win[i]);
560}
561
562int qed_init_fw_data(struct qed_dev *cdev, const u8 *data)
563{
564 struct qed_fw_data *fw = cdev->fw_data;
565 struct bin_buffer_hdr *buf_hdr;
566 u32 offset, len;
567
568 if (!data) {
569 DP_NOTICE(cdev, "Invalid fw data\n");
570 return -EINVAL;
571 }
572
573 /* First Dword contains metadata and should be skipped */
574 buf_hdr = (struct bin_buffer_hdr *)data;
575
576 offset = buf_hdr[BIN_BUF_INIT_FW_VER_INFO].offset;
577 fw->fw_ver_info = (struct fw_ver_info *)(data + offset);
578
579 offset = buf_hdr[BIN_BUF_INIT_CMD].offset;
580 fw->init_ops = (union init_op *)(data + offset);
581
582 offset = buf_hdr[BIN_BUF_INIT_VAL].offset;
583 fw->arr_data = (u32 *)(data + offset);
584
585 offset = buf_hdr[BIN_BUF_INIT_MODE_TREE].offset;
586 fw->modes_tree_buf = (u8 *)(data + offset);
587 len = buf_hdr[BIN_BUF_INIT_CMD].length;
588 fw->init_ops_size = len / sizeof(struct init_raw_op);
589
590 return 0;
591}