]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Copyright (c) 2016 QLogic Corporation. | |
3 | * All rights reserved. | |
4 | * www.qlogic.com | |
5 | * | |
6 | * See LICENSE.qede_pmd for copyright and licensing details. | |
7 | */ | |
8 | ||
9 | #include "bcm_osal.h" | |
10 | #include "ecore_hsi_common.h" | |
11 | #include "ecore_status.h" | |
12 | #include "ecore.h" | |
13 | #include "ecore_hw.h" | |
14 | #include "reg_addr.h" | |
15 | #include "ecore_utils.h" | |
16 | #include "ecore_iov_api.h" | |
17 | ||
18 | #ifndef ASIC_ONLY | |
19 | #define ECORE_EMUL_FACTOR 2000 | |
20 | #define ECORE_FPGA_FACTOR 200 | |
21 | #endif | |
22 | ||
23 | #define ECORE_BAR_ACQUIRE_TIMEOUT 1000 | |
24 | ||
25 | /* Invalid values */ | |
26 | #define ECORE_BAR_INVALID_OFFSET (OSAL_CPU_TO_LE32(-1)) | |
27 | ||
28 | struct ecore_ptt { | |
29 | osal_list_entry_t list_entry; | |
30 | unsigned int idx; | |
31 | struct pxp_ptt_entry pxp; | |
32 | u8 hwfn_id; | |
33 | }; | |
34 | ||
35 | struct ecore_ptt_pool { | |
36 | osal_list_t free_list; | |
37 | osal_spinlock_t lock; /* ptt synchronized access */ | |
38 | struct ecore_ptt ptts[PXP_EXTERNAL_BAR_PF_WINDOW_NUM]; | |
39 | }; | |
40 | ||
41 | enum _ecore_status_t ecore_ptt_pool_alloc(struct ecore_hwfn *p_hwfn) | |
42 | { | |
43 | struct ecore_ptt_pool *p_pool = OSAL_ALLOC(p_hwfn->p_dev, | |
44 | GFP_KERNEL, | |
45 | sizeof(*p_pool)); | |
46 | int i; | |
47 | ||
48 | if (!p_pool) | |
49 | return ECORE_NOMEM; | |
50 | ||
51 | OSAL_LIST_INIT(&p_pool->free_list); | |
52 | for (i = 0; i < PXP_EXTERNAL_BAR_PF_WINDOW_NUM; i++) { | |
53 | p_pool->ptts[i].idx = i; | |
54 | p_pool->ptts[i].pxp.offset = ECORE_BAR_INVALID_OFFSET; | |
55 | p_pool->ptts[i].pxp.pretend.control = 0; | |
56 | p_pool->ptts[i].hwfn_id = p_hwfn->my_id; | |
57 | ||
58 | /* There are special PTT entries that are taken only by design. | |
59 | * The rest are added ot the list for general usage. | |
60 | */ | |
61 | if (i >= RESERVED_PTT_MAX) | |
62 | OSAL_LIST_PUSH_HEAD(&p_pool->ptts[i].list_entry, | |
63 | &p_pool->free_list); | |
64 | } | |
65 | ||
66 | p_hwfn->p_ptt_pool = p_pool; | |
67 | OSAL_SPIN_LOCK_ALLOC(p_hwfn, &p_pool->lock); | |
68 | OSAL_SPIN_LOCK_INIT(&p_pool->lock); | |
69 | ||
70 | return ECORE_SUCCESS; | |
71 | } | |
72 | ||
73 | void ecore_ptt_invalidate(struct ecore_hwfn *p_hwfn) | |
74 | { | |
75 | struct ecore_ptt *p_ptt; | |
76 | int i; | |
77 | ||
78 | for (i = 0; i < PXP_EXTERNAL_BAR_PF_WINDOW_NUM; i++) { | |
79 | p_ptt = &p_hwfn->p_ptt_pool->ptts[i]; | |
80 | p_ptt->pxp.offset = ECORE_BAR_INVALID_OFFSET; | |
81 | } | |
82 | } | |
83 | ||
84 | void ecore_ptt_pool_free(struct ecore_hwfn *p_hwfn) | |
85 | { | |
86 | if (p_hwfn->p_ptt_pool) | |
87 | OSAL_SPIN_LOCK_DEALLOC(&p_hwfn->p_ptt_pool->lock); | |
88 | OSAL_FREE(p_hwfn->p_dev, p_hwfn->p_ptt_pool); | |
89 | p_hwfn->p_ptt_pool = OSAL_NULL; | |
90 | } | |
91 | ||
92 | struct ecore_ptt *ecore_ptt_acquire(struct ecore_hwfn *p_hwfn) | |
93 | { | |
94 | struct ecore_ptt *p_ptt; | |
95 | unsigned int i; | |
96 | ||
97 | /* Take the free PTT from the list */ | |
98 | for (i = 0; i < ECORE_BAR_ACQUIRE_TIMEOUT; i++) { | |
99 | OSAL_SPIN_LOCK(&p_hwfn->p_ptt_pool->lock); | |
100 | if (!OSAL_LIST_IS_EMPTY(&p_hwfn->p_ptt_pool->free_list)) { | |
101 | p_ptt = OSAL_LIST_FIRST_ENTRY( | |
102 | &p_hwfn->p_ptt_pool->free_list, | |
103 | struct ecore_ptt, list_entry); | |
104 | OSAL_LIST_REMOVE_ENTRY(&p_ptt->list_entry, | |
105 | &p_hwfn->p_ptt_pool->free_list); | |
106 | ||
107 | OSAL_SPIN_UNLOCK(&p_hwfn->p_ptt_pool->lock); | |
108 | ||
109 | DP_VERBOSE(p_hwfn, ECORE_MSG_HW, | |
110 | "allocated ptt %d\n", p_ptt->idx); | |
111 | ||
112 | return p_ptt; | |
113 | } | |
114 | ||
115 | OSAL_SPIN_UNLOCK(&p_hwfn->p_ptt_pool->lock); | |
116 | OSAL_MSLEEP(1); | |
117 | } | |
118 | ||
119 | DP_NOTICE(p_hwfn, true, | |
120 | "PTT acquire timeout - failed to allocate PTT\n"); | |
121 | return OSAL_NULL; | |
122 | } | |
123 | ||
124 | void ecore_ptt_release(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) | |
125 | { | |
126 | /* This PTT should not be set to pretend if it is being released */ | |
127 | /* TODO - add some pretend sanity checks, to make sure pretend | |
128 | * isn't set on this ptt | |
129 | */ | |
130 | ||
131 | OSAL_SPIN_LOCK(&p_hwfn->p_ptt_pool->lock); | |
132 | OSAL_LIST_PUSH_HEAD(&p_ptt->list_entry, &p_hwfn->p_ptt_pool->free_list); | |
133 | OSAL_SPIN_UNLOCK(&p_hwfn->p_ptt_pool->lock); | |
134 | } | |
135 | ||
136 | u32 ecore_ptt_get_hw_addr(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) | |
137 | { | |
138 | /* The HW is using DWORDS and we need to translate it to Bytes */ | |
139 | return OSAL_LE32_TO_CPU(p_ptt->pxp.offset) << 2; | |
140 | } | |
141 | ||
142 | static u32 ecore_ptt_config_addr(struct ecore_ptt *p_ptt) | |
143 | { | |
144 | return PXP_PF_WINDOW_ADMIN_PER_PF_START + | |
145 | p_ptt->idx * sizeof(struct pxp_ptt_entry); | |
146 | } | |
147 | ||
148 | u32 ecore_ptt_get_bar_addr(struct ecore_ptt *p_ptt) | |
149 | { | |
150 | return PXP_EXTERNAL_BAR_PF_WINDOW_START + | |
151 | p_ptt->idx * PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE; | |
152 | } | |
153 | ||
154 | void ecore_ptt_set_win(struct ecore_hwfn *p_hwfn, | |
155 | struct ecore_ptt *p_ptt, u32 new_hw_addr) | |
156 | { | |
157 | u32 prev_hw_addr; | |
158 | ||
159 | prev_hw_addr = ecore_ptt_get_hw_addr(p_hwfn, p_ptt); | |
160 | ||
161 | if (new_hw_addr == prev_hw_addr) | |
162 | return; | |
163 | ||
164 | /* Update PTT entery in admin window */ | |
165 | DP_VERBOSE(p_hwfn, ECORE_MSG_HW, | |
166 | "Updating PTT entry %d to offset 0x%x\n", | |
167 | p_ptt->idx, new_hw_addr); | |
168 | ||
169 | /* The HW is using DWORDS and the address is in Bytes */ | |
170 | p_ptt->pxp.offset = OSAL_CPU_TO_LE32(new_hw_addr >> 2); | |
171 | ||
172 | REG_WR(p_hwfn, | |
173 | ecore_ptt_config_addr(p_ptt) + | |
174 | OFFSETOF(struct pxp_ptt_entry, offset), | |
175 | OSAL_LE32_TO_CPU(p_ptt->pxp.offset)); | |
176 | } | |
177 | ||
178 | static u32 ecore_set_ptt(struct ecore_hwfn *p_hwfn, | |
179 | struct ecore_ptt *p_ptt, u32 hw_addr) | |
180 | { | |
181 | u32 win_hw_addr = ecore_ptt_get_hw_addr(p_hwfn, p_ptt); | |
182 | u32 offset; | |
183 | ||
184 | offset = hw_addr - win_hw_addr; | |
185 | ||
186 | if (p_ptt->hwfn_id != p_hwfn->my_id) | |
187 | DP_NOTICE(p_hwfn, true, | |
188 | "ptt[%d] of hwfn[%02x] is used by hwfn[%02x]!\n", | |
189 | p_ptt->idx, p_ptt->hwfn_id, p_hwfn->my_id); | |
190 | ||
191 | /* Verify the address is within the window */ | |
192 | if (hw_addr < win_hw_addr || | |
193 | offset >= PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE) { | |
194 | ecore_ptt_set_win(p_hwfn, p_ptt, hw_addr); | |
195 | offset = 0; | |
196 | } | |
197 | ||
198 | return ecore_ptt_get_bar_addr(p_ptt) + offset; | |
199 | } | |
200 | ||
201 | struct ecore_ptt *ecore_get_reserved_ptt(struct ecore_hwfn *p_hwfn, | |
202 | enum reserved_ptts ptt_idx) | |
203 | { | |
204 | if (ptt_idx >= RESERVED_PTT_MAX) { | |
205 | DP_NOTICE(p_hwfn, true, | |
206 | "Requested PTT %d is out of range\n", ptt_idx); | |
207 | return OSAL_NULL; | |
208 | } | |
209 | ||
210 | return &p_hwfn->p_ptt_pool->ptts[ptt_idx]; | |
211 | } | |
212 | ||
213 | static bool ecore_is_reg_fifo_empty(struct ecore_hwfn *p_hwfn, | |
214 | struct ecore_ptt *p_ptt) | |
215 | { | |
216 | bool is_empty = true; | |
217 | u32 bar_addr; | |
218 | ||
219 | if (!p_hwfn->p_dev->chk_reg_fifo) | |
220 | goto out; | |
221 | ||
222 | /* ecore_rd() cannot be used here since it calls this function */ | |
223 | bar_addr = ecore_set_ptt(p_hwfn, p_ptt, GRC_REG_TRACE_FIFO_VALID_DATA); | |
224 | is_empty = REG_RD(p_hwfn, bar_addr) == 0; | |
225 | ||
226 | #ifndef ASIC_ONLY | |
227 | if (CHIP_REV_IS_SLOW(p_hwfn->p_dev)) | |
228 | OSAL_UDELAY(100); | |
229 | #endif | |
230 | ||
231 | out: | |
232 | return is_empty; | |
233 | } | |
234 | ||
235 | void ecore_wr(struct ecore_hwfn *p_hwfn, | |
236 | struct ecore_ptt *p_ptt, u32 hw_addr, u32 val) | |
237 | { | |
238 | bool prev_fifo_err; | |
239 | u32 bar_addr; | |
240 | ||
241 | prev_fifo_err = !ecore_is_reg_fifo_empty(p_hwfn, p_ptt); | |
242 | ||
243 | bar_addr = ecore_set_ptt(p_hwfn, p_ptt, hw_addr); | |
244 | REG_WR(p_hwfn, bar_addr, val); | |
245 | DP_VERBOSE(p_hwfn, ECORE_MSG_HW, | |
246 | "bar_addr 0x%x, hw_addr 0x%x, val 0x%x\n", | |
247 | bar_addr, hw_addr, val); | |
248 | ||
249 | #ifndef ASIC_ONLY | |
250 | if (CHIP_REV_IS_SLOW(p_hwfn->p_dev)) | |
251 | OSAL_UDELAY(100); | |
252 | #endif | |
253 | ||
254 | OSAL_WARN(!prev_fifo_err && !ecore_is_reg_fifo_empty(p_hwfn, p_ptt), | |
255 | "reg_fifo err was caused by a call to ecore_wr(0x%x, 0x%x)\n", | |
256 | hw_addr, val); | |
257 | } | |
258 | ||
259 | u32 ecore_rd(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, u32 hw_addr) | |
260 | { | |
261 | bool prev_fifo_err; | |
262 | u32 bar_addr, val; | |
263 | ||
264 | prev_fifo_err = !ecore_is_reg_fifo_empty(p_hwfn, p_ptt); | |
265 | ||
266 | bar_addr = ecore_set_ptt(p_hwfn, p_ptt, hw_addr); | |
267 | val = REG_RD(p_hwfn, bar_addr); | |
268 | ||
269 | DP_VERBOSE(p_hwfn, ECORE_MSG_HW, | |
270 | "bar_addr 0x%x, hw_addr 0x%x, val 0x%x\n", | |
271 | bar_addr, hw_addr, val); | |
272 | ||
273 | #ifndef ASIC_ONLY | |
274 | if (CHIP_REV_IS_SLOW(p_hwfn->p_dev)) | |
275 | OSAL_UDELAY(100); | |
276 | #endif | |
277 | ||
278 | OSAL_WARN(!prev_fifo_err && !ecore_is_reg_fifo_empty(p_hwfn, p_ptt), | |
279 | "reg_fifo error was caused by a call to ecore_rd(0x%x)\n", | |
280 | hw_addr); | |
281 | ||
282 | return val; | |
283 | } | |
284 | ||
285 | static void ecore_memcpy_hw(struct ecore_hwfn *p_hwfn, | |
286 | struct ecore_ptt *p_ptt, | |
287 | void *addr, | |
288 | u32 hw_addr, osal_size_t n, bool to_device) | |
289 | { | |
290 | u32 dw_count, *host_addr, hw_offset; | |
291 | osal_size_t quota, done = 0; | |
292 | u32 OSAL_IOMEM *reg_addr; | |
293 | ||
294 | while (done < n) { | |
295 | quota = OSAL_MIN_T(osal_size_t, n - done, | |
296 | PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE); | |
297 | ||
298 | if (IS_PF(p_hwfn->p_dev)) { | |
299 | ecore_ptt_set_win(p_hwfn, p_ptt, hw_addr + done); | |
300 | hw_offset = ecore_ptt_get_bar_addr(p_ptt); | |
301 | } else { | |
302 | hw_offset = hw_addr + done; | |
303 | } | |
304 | ||
305 | dw_count = quota / 4; | |
306 | host_addr = (u32 *)((u8 *)addr + done); | |
307 | reg_addr = (u32 OSAL_IOMEM *)OSAL_REG_ADDR(p_hwfn, hw_offset); | |
308 | ||
309 | if (to_device) | |
310 | while (dw_count--) | |
311 | DIRECT_REG_WR(p_hwfn, reg_addr++, *host_addr++); | |
312 | else | |
313 | while (dw_count--) | |
314 | *host_addr++ = DIRECT_REG_RD(p_hwfn, | |
315 | reg_addr++); | |
316 | ||
317 | done += quota; | |
318 | } | |
319 | } | |
320 | ||
321 | void ecore_memcpy_from(struct ecore_hwfn *p_hwfn, | |
322 | struct ecore_ptt *p_ptt, | |
323 | void *dest, u32 hw_addr, osal_size_t n) | |
324 | { | |
325 | DP_VERBOSE(p_hwfn, ECORE_MSG_HW, | |
326 | "hw_addr 0x%x, dest %p hw_addr 0x%x, size %lu\n", | |
327 | hw_addr, dest, hw_addr, (unsigned long)n); | |
328 | ||
329 | ecore_memcpy_hw(p_hwfn, p_ptt, dest, hw_addr, n, false); | |
330 | } | |
331 | ||
332 | void ecore_memcpy_to(struct ecore_hwfn *p_hwfn, | |
333 | struct ecore_ptt *p_ptt, | |
334 | u32 hw_addr, void *src, osal_size_t n) | |
335 | { | |
336 | DP_VERBOSE(p_hwfn, ECORE_MSG_HW, | |
337 | "hw_addr 0x%x, hw_addr 0x%x, src %p size %lu\n", | |
338 | hw_addr, hw_addr, src, (unsigned long)n); | |
339 | ||
340 | ecore_memcpy_hw(p_hwfn, p_ptt, src, hw_addr, n, true); | |
341 | } | |
342 | ||
343 | void ecore_fid_pretend(struct ecore_hwfn *p_hwfn, | |
344 | struct ecore_ptt *p_ptt, u16 fid) | |
345 | { | |
346 | u16 control = 0; | |
347 | ||
348 | SET_FIELD(control, PXP_PRETEND_CMD_IS_CONCRETE, 1); | |
349 | SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_FUNCTION, 1); | |
350 | ||
351 | /* Every pretend undos prev pretends, including previous port pretend */ | |
352 | ||
353 | SET_FIELD(control, PXP_PRETEND_CMD_PORT, 0); | |
354 | SET_FIELD(control, PXP_PRETEND_CMD_USE_PORT, 0); | |
355 | SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_PORT, 1); | |
356 | ||
357 | if (!GET_FIELD(fid, PXP_CONCRETE_FID_VFVALID)) | |
358 | fid = GET_FIELD(fid, PXP_CONCRETE_FID_PFID); | |
359 | ||
360 | p_ptt->pxp.pretend.control = OSAL_CPU_TO_LE16(control); | |
361 | p_ptt->pxp.pretend.fid.concrete_fid.fid = OSAL_CPU_TO_LE16(fid); | |
362 | ||
363 | REG_WR(p_hwfn, | |
364 | ecore_ptt_config_addr(p_ptt) + | |
365 | OFFSETOF(struct pxp_ptt_entry, pretend), | |
366 | *(u32 *)&p_ptt->pxp.pretend); | |
367 | } | |
368 | ||
369 | void ecore_port_pretend(struct ecore_hwfn *p_hwfn, | |
370 | struct ecore_ptt *p_ptt, u8 port_id) | |
371 | { | |
372 | u16 control = 0; | |
373 | ||
374 | SET_FIELD(control, PXP_PRETEND_CMD_PORT, port_id); | |
375 | SET_FIELD(control, PXP_PRETEND_CMD_USE_PORT, 1); | |
376 | SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_PORT, 1); | |
377 | p_ptt->pxp.pretend.control = OSAL_CPU_TO_LE16(control); | |
378 | ||
379 | REG_WR(p_hwfn, | |
380 | ecore_ptt_config_addr(p_ptt) + | |
381 | OFFSETOF(struct pxp_ptt_entry, pretend), | |
382 | *(u32 *)&p_ptt->pxp.pretend); | |
383 | } | |
384 | ||
385 | void ecore_port_unpretend(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) | |
386 | { | |
387 | u16 control = 0; | |
388 | ||
389 | SET_FIELD(control, PXP_PRETEND_CMD_PORT, 0); | |
390 | SET_FIELD(control, PXP_PRETEND_CMD_USE_PORT, 0); | |
391 | SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_PORT, 1); | |
392 | ||
393 | p_ptt->pxp.pretend.control = OSAL_CPU_TO_LE16(control); | |
394 | ||
395 | REG_WR(p_hwfn, | |
396 | ecore_ptt_config_addr(p_ptt) + | |
397 | OFFSETOF(struct pxp_ptt_entry, pretend), | |
398 | *(u32 *)&p_ptt->pxp.pretend); | |
399 | } | |
400 | ||
401 | u32 ecore_vfid_to_concrete(struct ecore_hwfn *p_hwfn, u8 vfid) | |
402 | { | |
403 | u32 concrete_fid = 0; | |
404 | ||
405 | SET_FIELD(concrete_fid, PXP_CONCRETE_FID_PFID, p_hwfn->rel_pf_id); | |
406 | SET_FIELD(concrete_fid, PXP_CONCRETE_FID_VFID, vfid); | |
407 | SET_FIELD(concrete_fid, PXP_CONCRETE_FID_VFVALID, 1); | |
408 | ||
409 | return concrete_fid; | |
410 | } | |
411 | ||
412 | /* Not in use @DPDK | |
413 | * Ecore HW lock | |
414 | * ============= | |
415 | * Although the implementation is ready, today we don't have any flow that | |
416 | * utliizes said locks - and we want to keep it this way. | |
417 | * If this changes, this needs to be revisted. | |
418 | */ | |
419 | ||
420 | /* Ecore DMAE | |
421 | * ============= | |
422 | */ | |
423 | static void ecore_dmae_opcode(struct ecore_hwfn *p_hwfn, | |
424 | const u8 is_src_type_grc, | |
425 | const u8 is_dst_type_grc, | |
426 | struct ecore_dmae_params *p_params) | |
427 | { | |
428 | u16 opcode_b = 0; | |
429 | u32 opcode = 0; | |
430 | ||
431 | /* Whether the source is the PCIe or the GRC. | |
432 | * 0- The source is the PCIe | |
433 | * 1- The source is the GRC. | |
434 | */ | |
435 | opcode |= (is_src_type_grc ? DMAE_CMD_SRC_MASK_GRC | |
436 | : DMAE_CMD_SRC_MASK_PCIE) << DMAE_CMD_SRC_SHIFT; | |
437 | opcode |= (p_hwfn->rel_pf_id & DMAE_CMD_SRC_PF_ID_MASK) << | |
438 | DMAE_CMD_SRC_PF_ID_SHIFT; | |
439 | ||
440 | /* The destination of the DMA can be: 0-None 1-PCIe 2-GRC 3-None */ | |
441 | opcode |= (is_dst_type_grc ? DMAE_CMD_DST_MASK_GRC | |
442 | : DMAE_CMD_DST_MASK_PCIE) << DMAE_CMD_DST_SHIFT; | |
443 | opcode |= (p_hwfn->rel_pf_id & DMAE_CMD_DST_PF_ID_MASK) << | |
444 | DMAE_CMD_DST_PF_ID_SHIFT; | |
445 | ||
446 | /* DMAE_E4_TODO need to check which value to specifiy here. */ | |
447 | /* opcode |= (!b_complete_to_host)<< DMAE_CMD_C_DST_SHIFT; */ | |
448 | ||
449 | /* Whether to write a completion word to the completion destination: | |
450 | * 0-Do not write a completion word | |
451 | * 1-Write the completion word | |
452 | */ | |
453 | opcode |= DMAE_CMD_COMP_WORD_EN_MASK << DMAE_CMD_COMP_WORD_EN_SHIFT; | |
454 | opcode |= DMAE_CMD_SRC_ADDR_RESET_MASK << DMAE_CMD_SRC_ADDR_RESET_SHIFT; | |
455 | ||
456 | if (p_params->flags & ECORE_DMAE_FLAG_COMPLETION_DST) | |
457 | opcode |= 1 << DMAE_CMD_COMP_FUNC_SHIFT; | |
458 | ||
459 | /* swapping mode 3 - big endian there should be a define ifdefed in | |
460 | * the HSI somewhere. Since it is currently | |
461 | */ | |
462 | opcode |= DMAE_CMD_ENDIANITY << DMAE_CMD_ENDIANITY_MODE_SHIFT; | |
463 | ||
464 | opcode |= p_hwfn->port_id << DMAE_CMD_PORT_ID_SHIFT; | |
465 | ||
466 | /* reset source address in next go */ | |
467 | opcode |= DMAE_CMD_SRC_ADDR_RESET_MASK << DMAE_CMD_SRC_ADDR_RESET_SHIFT; | |
468 | ||
469 | /* reset dest address in next go */ | |
470 | opcode |= DMAE_CMD_DST_ADDR_RESET_MASK << DMAE_CMD_DST_ADDR_RESET_SHIFT; | |
471 | ||
472 | /* SRC/DST VFID: all 1's - pf, otherwise VF id */ | |
473 | if (p_params->flags & ECORE_DMAE_FLAG_VF_SRC) { | |
474 | opcode |= (1 << DMAE_CMD_SRC_VF_ID_VALID_SHIFT); | |
475 | opcode_b |= (p_params->src_vfid << DMAE_CMD_SRC_VF_ID_SHIFT); | |
476 | } else { | |
477 | opcode_b |= (DMAE_CMD_SRC_VF_ID_MASK << | |
478 | DMAE_CMD_SRC_VF_ID_SHIFT); | |
479 | } | |
480 | if (p_params->flags & ECORE_DMAE_FLAG_VF_DST) { | |
481 | opcode |= 1 << DMAE_CMD_DST_VF_ID_VALID_SHIFT; | |
482 | opcode_b |= p_params->dst_vfid << DMAE_CMD_DST_VF_ID_SHIFT; | |
483 | } else { | |
484 | opcode_b |= DMAE_CMD_DST_VF_ID_MASK << DMAE_CMD_DST_VF_ID_SHIFT; | |
485 | } | |
486 | ||
487 | p_hwfn->dmae_info.p_dmae_cmd->opcode = OSAL_CPU_TO_LE32(opcode); | |
488 | p_hwfn->dmae_info.p_dmae_cmd->opcode_b = OSAL_CPU_TO_LE16(opcode_b); | |
489 | } | |
490 | ||
491 | static u32 ecore_dmae_idx_to_go_cmd(u8 idx) | |
492 | { | |
493 | OSAL_BUILD_BUG_ON((DMAE_REG_GO_C31 - DMAE_REG_GO_C0) != 31 * 4); | |
494 | ||
495 | /* All the DMAE 'go' registers form an array in internal memory */ | |
496 | return DMAE_REG_GO_C0 + (idx << 2); | |
497 | } | |
498 | ||
499 | static enum _ecore_status_t | |
500 | ecore_dmae_post_command(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) | |
501 | { | |
502 | struct dmae_cmd *p_command = p_hwfn->dmae_info.p_dmae_cmd; | |
503 | u8 idx_cmd = p_hwfn->dmae_info.channel, i; | |
504 | enum _ecore_status_t ecore_status = ECORE_SUCCESS; | |
505 | ||
506 | /* verify address is not OSAL_NULL */ | |
507 | if ((((!p_command->dst_addr_lo) && (!p_command->dst_addr_hi)) || | |
508 | ((!p_command->src_addr_lo) && (!p_command->src_addr_hi)))) { | |
509 | DP_NOTICE(p_hwfn, true, | |
510 | "source or destination address 0 idx_cmd=%d\n" | |
511 | "opcode = [0x%08x,0x%04x] len=0x%x" | |
512 | " src=0x%x:%x dst=0x%x:%x\n", | |
513 | idx_cmd, | |
514 | OSAL_LE32_TO_CPU(p_command->opcode), | |
515 | OSAL_LE16_TO_CPU(p_command->opcode_b), | |
516 | OSAL_LE16_TO_CPU(p_command->length_dw), | |
517 | OSAL_LE32_TO_CPU(p_command->src_addr_hi), | |
518 | OSAL_LE32_TO_CPU(p_command->src_addr_lo), | |
519 | OSAL_LE32_TO_CPU(p_command->dst_addr_hi), | |
520 | OSAL_LE32_TO_CPU(p_command->dst_addr_lo)); | |
521 | ||
522 | return ECORE_INVAL; | |
523 | } | |
524 | ||
525 | DP_VERBOSE(p_hwfn, ECORE_MSG_HW, | |
526 | "Posting DMAE command [idx %d]: opcode = [0x%08x,0x%04x]" | |
527 | "len=0x%x src=0x%x:%x dst=0x%x:%x\n", | |
528 | idx_cmd, | |
529 | OSAL_LE32_TO_CPU(p_command->opcode), | |
530 | OSAL_LE16_TO_CPU(p_command->opcode_b), | |
531 | OSAL_LE16_TO_CPU(p_command->length_dw), | |
532 | OSAL_LE32_TO_CPU(p_command->src_addr_hi), | |
533 | OSAL_LE32_TO_CPU(p_command->src_addr_lo), | |
534 | OSAL_LE32_TO_CPU(p_command->dst_addr_hi), | |
535 | OSAL_LE32_TO_CPU(p_command->dst_addr_lo)); | |
536 | ||
537 | /* Copy the command to DMAE - need to do it before every call | |
538 | * for source/dest address no reset. | |
539 | * The number of commands have been increased to 16 (previous was 14) | |
540 | * The first 9 DWs are the command registers, the 10 DW is the | |
541 | * GO register, and | |
542 | * the rest are result registers (which are read only by the client). | |
543 | */ | |
544 | for (i = 0; i < DMAE_CMD_SIZE; i++) { | |
545 | u32 data = (i < DMAE_CMD_SIZE_TO_FILL) ? | |
546 | *(((u32 *)p_command) + i) : 0; | |
547 | ||
548 | ecore_wr(p_hwfn, p_ptt, | |
549 | DMAE_REG_CMD_MEM + | |
550 | (idx_cmd * DMAE_CMD_SIZE * sizeof(u32)) + | |
551 | (i * sizeof(u32)), data); | |
552 | } | |
553 | ||
554 | ecore_wr(p_hwfn, p_ptt, | |
555 | ecore_dmae_idx_to_go_cmd(idx_cmd), DMAE_GO_VALUE); | |
556 | ||
557 | return ecore_status; | |
558 | } | |
559 | ||
560 | enum _ecore_status_t ecore_dmae_info_alloc(struct ecore_hwfn *p_hwfn) | |
561 | { | |
562 | dma_addr_t *p_addr = &p_hwfn->dmae_info.completion_word_phys_addr; | |
563 | struct dmae_cmd **p_cmd = &p_hwfn->dmae_info.p_dmae_cmd; | |
564 | u32 **p_buff = &p_hwfn->dmae_info.p_intermediate_buffer; | |
565 | u32 **p_comp = &p_hwfn->dmae_info.p_completion_word; | |
566 | ||
567 | *p_comp = OSAL_DMA_ALLOC_COHERENT(p_hwfn->p_dev, p_addr, sizeof(u32)); | |
568 | if (*p_comp == OSAL_NULL) { | |
569 | DP_NOTICE(p_hwfn, true, | |
570 | "Failed to allocate `p_completion_word'\n"); | |
571 | goto err; | |
572 | } | |
573 | ||
574 | p_addr = &p_hwfn->dmae_info.dmae_cmd_phys_addr; | |
575 | *p_cmd = OSAL_DMA_ALLOC_COHERENT(p_hwfn->p_dev, p_addr, | |
576 | sizeof(struct dmae_cmd)); | |
577 | if (*p_cmd == OSAL_NULL) { | |
578 | DP_NOTICE(p_hwfn, true, | |
579 | "Failed to allocate `struct dmae_cmd'\n"); | |
580 | goto err; | |
581 | } | |
582 | ||
583 | p_addr = &p_hwfn->dmae_info.intermediate_buffer_phys_addr; | |
584 | *p_buff = OSAL_DMA_ALLOC_COHERENT(p_hwfn->p_dev, p_addr, | |
585 | sizeof(u32) * DMAE_MAX_RW_SIZE); | |
586 | if (*p_buff == OSAL_NULL) { | |
587 | DP_NOTICE(p_hwfn, true, | |
588 | "Failed to allocate `intermediate_buffer'\n"); | |
589 | goto err; | |
590 | } | |
591 | ||
592 | p_hwfn->dmae_info.channel = p_hwfn->rel_pf_id; | |
593 | ||
594 | return ECORE_SUCCESS; | |
595 | err: | |
596 | ecore_dmae_info_free(p_hwfn); | |
597 | return ECORE_NOMEM; | |
598 | } | |
599 | ||
600 | void ecore_dmae_info_free(struct ecore_hwfn *p_hwfn) | |
601 | { | |
602 | dma_addr_t p_phys; | |
603 | ||
604 | /* Just make sure no one is in the middle */ | |
605 | OSAL_MUTEX_ACQUIRE(&p_hwfn->dmae_info.mutex); | |
606 | ||
607 | if (p_hwfn->dmae_info.p_completion_word != OSAL_NULL) { | |
608 | p_phys = p_hwfn->dmae_info.completion_word_phys_addr; | |
609 | OSAL_DMA_FREE_COHERENT(p_hwfn->p_dev, | |
610 | p_hwfn->dmae_info.p_completion_word, | |
611 | p_phys, sizeof(u32)); | |
612 | p_hwfn->dmae_info.p_completion_word = OSAL_NULL; | |
613 | } | |
614 | ||
615 | if (p_hwfn->dmae_info.p_dmae_cmd != OSAL_NULL) { | |
616 | p_phys = p_hwfn->dmae_info.dmae_cmd_phys_addr; | |
617 | OSAL_DMA_FREE_COHERENT(p_hwfn->p_dev, | |
618 | p_hwfn->dmae_info.p_dmae_cmd, | |
619 | p_phys, sizeof(struct dmae_cmd)); | |
620 | p_hwfn->dmae_info.p_dmae_cmd = OSAL_NULL; | |
621 | } | |
622 | ||
623 | if (p_hwfn->dmae_info.p_intermediate_buffer != OSAL_NULL) { | |
624 | p_phys = p_hwfn->dmae_info.intermediate_buffer_phys_addr; | |
625 | OSAL_DMA_FREE_COHERENT(p_hwfn->p_dev, | |
626 | p_hwfn->dmae_info.p_intermediate_buffer, | |
627 | p_phys, sizeof(u32) * DMAE_MAX_RW_SIZE); | |
628 | p_hwfn->dmae_info.p_intermediate_buffer = OSAL_NULL; | |
629 | } | |
630 | ||
631 | OSAL_MUTEX_RELEASE(&p_hwfn->dmae_info.mutex); | |
632 | } | |
633 | ||
634 | static enum _ecore_status_t ecore_dmae_operation_wait(struct ecore_hwfn *p_hwfn) | |
635 | { | |
636 | u32 wait_cnt_limit = 10000, wait_cnt = 0; | |
637 | enum _ecore_status_t ecore_status = ECORE_SUCCESS; | |
638 | ||
639 | #ifndef ASIC_ONLY | |
640 | u32 factor = (CHIP_REV_IS_EMUL(p_hwfn->p_dev) ? | |
641 | ECORE_EMUL_FACTOR : | |
642 | (CHIP_REV_IS_FPGA(p_hwfn->p_dev) ? | |
643 | ECORE_FPGA_FACTOR : 1)); | |
644 | ||
645 | wait_cnt_limit *= factor; | |
646 | #endif | |
647 | ||
648 | /* DMAE_E4_TODO : TODO check if we have to call any other function | |
649 | * other than BARRIER to sync the completion_word since we are not | |
650 | * using the volatile keyword for this | |
651 | */ | |
652 | OSAL_BARRIER(p_hwfn->p_dev); | |
653 | while (*p_hwfn->dmae_info.p_completion_word != DMAE_COMPLETION_VAL) { | |
654 | OSAL_UDELAY(DMAE_MIN_WAIT_TIME); | |
655 | if (++wait_cnt > wait_cnt_limit) { | |
656 | DP_NOTICE(p_hwfn->p_dev, ECORE_MSG_HW, | |
657 | "Timed-out waiting for operation to" | |
658 | " complete. Completion word is 0x%08x" | |
659 | " expected 0x%08x.\n", | |
660 | *p_hwfn->dmae_info.p_completion_word, | |
661 | DMAE_COMPLETION_VAL); | |
662 | ecore_status = ECORE_TIMEOUT; | |
663 | break; | |
664 | } | |
665 | /* to sync the completion_word since we are not | |
666 | * using the volatile keyword for p_completion_word | |
667 | */ | |
668 | OSAL_BARRIER(p_hwfn->p_dev); | |
669 | } | |
670 | ||
671 | if (ecore_status == ECORE_SUCCESS) | |
672 | *p_hwfn->dmae_info.p_completion_word = 0; | |
673 | ||
674 | return ecore_status; | |
675 | } | |
676 | ||
677 | static enum _ecore_status_t | |
678 | ecore_dmae_execute_sub_operation(struct ecore_hwfn *p_hwfn, | |
679 | struct ecore_ptt *p_ptt, | |
680 | u64 src_addr, | |
681 | u64 dst_addr, | |
682 | u8 src_type, u8 dst_type, u32 length_dw) | |
683 | { | |
684 | dma_addr_t phys = p_hwfn->dmae_info.intermediate_buffer_phys_addr; | |
685 | struct dmae_cmd *cmd = p_hwfn->dmae_info.p_dmae_cmd; | |
686 | enum _ecore_status_t ecore_status = ECORE_SUCCESS; | |
687 | ||
688 | switch (src_type) { | |
689 | case ECORE_DMAE_ADDRESS_GRC: | |
690 | case ECORE_DMAE_ADDRESS_HOST_PHYS: | |
691 | cmd->src_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(src_addr)); | |
692 | cmd->src_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(src_addr)); | |
693 | break; | |
694 | /* for virt source addresses we use the intermediate buffer. */ | |
695 | case ECORE_DMAE_ADDRESS_HOST_VIRT: | |
696 | cmd->src_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(phys)); | |
697 | cmd->src_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(phys)); | |
698 | OSAL_MEMCPY(&p_hwfn->dmae_info.p_intermediate_buffer[0], | |
699 | (void *)(osal_uintptr_t)src_addr, | |
700 | length_dw * sizeof(u32)); | |
701 | break; | |
702 | default: | |
703 | return ECORE_INVAL; | |
704 | } | |
705 | ||
706 | switch (dst_type) { | |
707 | case ECORE_DMAE_ADDRESS_GRC: | |
708 | case ECORE_DMAE_ADDRESS_HOST_PHYS: | |
709 | cmd->dst_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(dst_addr)); | |
710 | cmd->dst_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(dst_addr)); | |
711 | break; | |
712 | /* for virt destination address we use the intermediate buff. */ | |
713 | case ECORE_DMAE_ADDRESS_HOST_VIRT: | |
714 | cmd->dst_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(phys)); | |
715 | cmd->dst_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(phys)); | |
716 | break; | |
717 | default: | |
718 | return ECORE_INVAL; | |
719 | } | |
720 | ||
721 | cmd->length_dw = OSAL_CPU_TO_LE16((u16)length_dw); | |
722 | ||
723 | if (src_type == ECORE_DMAE_ADDRESS_HOST_VIRT || | |
724 | src_type == ECORE_DMAE_ADDRESS_HOST_PHYS) | |
725 | OSAL_DMA_SYNC(p_hwfn->p_dev, | |
726 | (void *)HILO_U64(cmd->src_addr_hi, | |
727 | cmd->src_addr_lo), | |
728 | length_dw * sizeof(u32), false); | |
729 | ||
730 | ecore_dmae_post_command(p_hwfn, p_ptt); | |
731 | ||
732 | ecore_status = ecore_dmae_operation_wait(p_hwfn); | |
733 | ||
734 | /* TODO - is it true ? */ | |
735 | if (src_type == ECORE_DMAE_ADDRESS_HOST_VIRT || | |
736 | src_type == ECORE_DMAE_ADDRESS_HOST_PHYS) | |
737 | OSAL_DMA_SYNC(p_hwfn->p_dev, | |
738 | (void *)HILO_U64(cmd->src_addr_hi, | |
739 | cmd->src_addr_lo), | |
740 | length_dw * sizeof(u32), true); | |
741 | ||
742 | if (ecore_status != ECORE_SUCCESS) { | |
743 | DP_NOTICE(p_hwfn, ECORE_MSG_HW, | |
744 | "ecore_dmae_host2grc: Wait Failed. source_addr" | |
745 | " 0x%lx, grc_addr 0x%lx, size_in_dwords 0x%x\n", | |
746 | (unsigned long)src_addr, (unsigned long)dst_addr, | |
747 | length_dw); | |
748 | return ecore_status; | |
749 | } | |
750 | ||
751 | if (dst_type == ECORE_DMAE_ADDRESS_HOST_VIRT) | |
752 | OSAL_MEMCPY((void *)(osal_uintptr_t)(dst_addr), | |
753 | &p_hwfn->dmae_info.p_intermediate_buffer[0], | |
754 | length_dw * sizeof(u32)); | |
755 | ||
756 | return ECORE_SUCCESS; | |
757 | } | |
758 | ||
759 | static enum _ecore_status_t | |
760 | ecore_dmae_execute_command(struct ecore_hwfn *p_hwfn, | |
761 | struct ecore_ptt *p_ptt, | |
762 | u64 src_addr, | |
763 | u64 dst_addr, | |
764 | u8 src_type, | |
765 | u8 dst_type, | |
766 | u32 size_in_dwords, | |
767 | struct ecore_dmae_params *p_params) | |
768 | { | |
769 | dma_addr_t phys = p_hwfn->dmae_info.completion_word_phys_addr; | |
770 | u16 length_cur = 0, i = 0, cnt_split = 0, length_mod = 0; | |
771 | struct dmae_cmd *cmd = p_hwfn->dmae_info.p_dmae_cmd; | |
772 | u64 src_addr_split = 0, dst_addr_split = 0; | |
773 | u16 length_limit = DMAE_MAX_RW_SIZE; | |
774 | enum _ecore_status_t ecore_status = ECORE_SUCCESS; | |
775 | u32 offset = 0; | |
776 | ||
777 | ecore_dmae_opcode(p_hwfn, | |
778 | (src_type == ECORE_DMAE_ADDRESS_GRC), | |
779 | (dst_type == ECORE_DMAE_ADDRESS_GRC), p_params); | |
780 | ||
781 | cmd->comp_addr_lo = OSAL_CPU_TO_LE32(DMA_LO(phys)); | |
782 | cmd->comp_addr_hi = OSAL_CPU_TO_LE32(DMA_HI(phys)); | |
783 | cmd->comp_val = OSAL_CPU_TO_LE32(DMAE_COMPLETION_VAL); | |
784 | ||
785 | /* Check if the grc_addr is valid like < MAX_GRC_OFFSET */ | |
786 | cnt_split = size_in_dwords / length_limit; | |
787 | length_mod = size_in_dwords % length_limit; | |
788 | ||
789 | src_addr_split = src_addr; | |
790 | dst_addr_split = dst_addr; | |
791 | ||
792 | for (i = 0; i <= cnt_split; i++) { | |
793 | offset = length_limit * i; | |
794 | ||
795 | if (!(p_params->flags & ECORE_DMAE_FLAG_RW_REPL_SRC)) { | |
796 | if (src_type == ECORE_DMAE_ADDRESS_GRC) | |
797 | src_addr_split = src_addr + offset; | |
798 | else | |
799 | src_addr_split = src_addr + (offset * 4); | |
800 | } | |
801 | ||
802 | if (dst_type == ECORE_DMAE_ADDRESS_GRC) | |
803 | dst_addr_split = dst_addr + offset; | |
804 | else | |
805 | dst_addr_split = dst_addr + (offset * 4); | |
806 | ||
807 | length_cur = (cnt_split == i) ? length_mod : length_limit; | |
808 | ||
809 | /* might be zero on last iteration */ | |
810 | if (!length_cur) | |
811 | continue; | |
812 | ||
813 | ecore_status = ecore_dmae_execute_sub_operation(p_hwfn, | |
814 | p_ptt, | |
815 | src_addr_split, | |
816 | dst_addr_split, | |
817 | src_type, | |
818 | dst_type, | |
819 | length_cur); | |
820 | if (ecore_status != ECORE_SUCCESS) { | |
821 | DP_NOTICE(p_hwfn, false, | |
822 | "ecore_dmae_execute_sub_operation Failed" | |
823 | " with error 0x%x. source_addr 0x%lx," | |
824 | " dest addr 0x%lx, size_in_dwords 0x%x\n", | |
825 | ecore_status, (unsigned long)src_addr, | |
826 | (unsigned long)dst_addr, length_cur); | |
827 | ||
828 | ecore_hw_err_notify(p_hwfn, ECORE_HW_ERR_DMAE_FAIL); | |
829 | break; | |
830 | } | |
831 | } | |
832 | ||
833 | return ecore_status; | |
834 | } | |
835 | ||
836 | enum _ecore_status_t | |
837 | ecore_dmae_host2grc(struct ecore_hwfn *p_hwfn, | |
838 | struct ecore_ptt *p_ptt, | |
839 | u64 source_addr, | |
840 | u32 grc_addr, u32 size_in_dwords, u32 flags) | |
841 | { | |
842 | u32 grc_addr_in_dw = grc_addr / sizeof(u32); | |
843 | struct ecore_dmae_params params; | |
844 | enum _ecore_status_t rc; | |
845 | ||
846 | OSAL_MEMSET(¶ms, 0, sizeof(struct ecore_dmae_params)); | |
847 | params.flags = flags; | |
848 | ||
849 | OSAL_MUTEX_ACQUIRE(&p_hwfn->dmae_info.mutex); | |
850 | ||
851 | rc = ecore_dmae_execute_command(p_hwfn, p_ptt, source_addr, | |
852 | grc_addr_in_dw, | |
853 | ECORE_DMAE_ADDRESS_HOST_VIRT, | |
854 | ECORE_DMAE_ADDRESS_GRC, | |
855 | size_in_dwords, ¶ms); | |
856 | ||
857 | OSAL_MUTEX_RELEASE(&p_hwfn->dmae_info.mutex); | |
858 | ||
859 | return rc; | |
860 | } | |
861 | ||
862 | enum _ecore_status_t | |
863 | ecore_dmae_grc2host(struct ecore_hwfn *p_hwfn, | |
864 | struct ecore_ptt *p_ptt, | |
865 | u32 grc_addr, | |
866 | dma_addr_t dest_addr, u32 size_in_dwords, u32 flags) | |
867 | { | |
868 | u32 grc_addr_in_dw = grc_addr / sizeof(u32); | |
869 | struct ecore_dmae_params params; | |
870 | enum _ecore_status_t rc; | |
871 | ||
872 | OSAL_MEMSET(¶ms, 0, sizeof(struct ecore_dmae_params)); | |
873 | params.flags = flags; | |
874 | ||
875 | OSAL_MUTEX_ACQUIRE(&p_hwfn->dmae_info.mutex); | |
876 | ||
877 | rc = ecore_dmae_execute_command(p_hwfn, p_ptt, grc_addr_in_dw, | |
878 | dest_addr, ECORE_DMAE_ADDRESS_GRC, | |
879 | ECORE_DMAE_ADDRESS_HOST_VIRT, | |
880 | size_in_dwords, ¶ms); | |
881 | ||
882 | OSAL_MUTEX_RELEASE(&p_hwfn->dmae_info.mutex); | |
883 | ||
884 | return rc; | |
885 | } | |
886 | ||
887 | enum _ecore_status_t | |
888 | ecore_dmae_host2host(struct ecore_hwfn *p_hwfn, | |
889 | struct ecore_ptt *p_ptt, | |
890 | dma_addr_t source_addr, | |
891 | dma_addr_t dest_addr, | |
892 | u32 size_in_dwords, struct ecore_dmae_params *p_params) | |
893 | { | |
894 | enum _ecore_status_t rc; | |
895 | ||
896 | OSAL_MUTEX_ACQUIRE(&p_hwfn->dmae_info.mutex); | |
897 | ||
898 | rc = ecore_dmae_execute_command(p_hwfn, p_ptt, source_addr, | |
899 | dest_addr, | |
900 | ECORE_DMAE_ADDRESS_HOST_PHYS, | |
901 | ECORE_DMAE_ADDRESS_HOST_PHYS, | |
902 | size_in_dwords, p_params); | |
903 | ||
904 | OSAL_MUTEX_RELEASE(&p_hwfn->dmae_info.mutex); | |
905 | ||
906 | return rc; | |
907 | } | |
908 | ||
909 | u16 ecore_get_qm_pq(struct ecore_hwfn *p_hwfn, | |
910 | enum protocol_type proto, | |
911 | union ecore_qm_pq_params *p_params) | |
912 | { | |
913 | u16 pq_id = 0; | |
914 | ||
915 | if ((proto == PROTOCOLID_CORE || | |
916 | proto == PROTOCOLID_ETH) && !p_params) { | |
917 | DP_NOTICE(p_hwfn, true, | |
918 | "Protocol %d received NULL PQ params\n", proto); | |
919 | return 0; | |
920 | } | |
921 | ||
922 | switch (proto) { | |
923 | case PROTOCOLID_CORE: | |
924 | if (p_params->core.tc == LB_TC) | |
925 | pq_id = p_hwfn->qm_info.pure_lb_pq; | |
926 | else if (p_params->core.tc == OOO_LB_TC) | |
927 | pq_id = p_hwfn->qm_info.ooo_pq; | |
928 | else | |
929 | pq_id = p_hwfn->qm_info.offload_pq; | |
930 | break; | |
931 | case PROTOCOLID_ETH: | |
932 | pq_id = p_params->eth.tc; | |
933 | /* TODO - multi-CoS for VFs? */ | |
934 | if (p_params->eth.is_vf) | |
935 | pq_id += p_hwfn->qm_info.vf_queues_offset + | |
936 | p_params->eth.vf_id; | |
937 | break; | |
938 | default: | |
939 | pq_id = 0; | |
940 | } | |
941 | ||
942 | pq_id = CM_TX_PQ_BASE + pq_id + RESC_START(p_hwfn, ECORE_PQ); | |
943 | ||
944 | return pq_id; | |
945 | } | |
946 | ||
947 | void ecore_hw_err_notify(struct ecore_hwfn *p_hwfn, | |
948 | enum ecore_hw_err_type err_type) | |
949 | { | |
950 | /* Fan failure cannot be masked by handling of another HW error */ | |
951 | if (p_hwfn->p_dev->recov_in_prog && err_type != ECORE_HW_ERR_FAN_FAIL) { | |
952 | DP_VERBOSE(p_hwfn, ECORE_MSG_DRV, | |
953 | "Recovery is in progress." | |
954 | "Avoid notifying about HW error %d.\n", | |
955 | err_type); | |
956 | return; | |
957 | } | |
958 | ||
959 | OSAL_HW_ERROR_OCCURRED(p_hwfn, err_type); | |
960 | } |