Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2025 Huawei Technologies Co., Ltd
3 : : */
4 : : #include <unistd.h>
5 : : #include "hinic3_compat.h"
6 : : #include "hinic3_csr.h"
7 : : #include "hinic3_eqs.h"
8 : : #include "hinic3_hwdev.h"
9 : : #include "hinic3_hwif.h"
10 : : #include "hinic3_mbox.h"
11 : : #include "hinic3_mgmt.h"
12 : : #include "hinic3_nic_event.h"
13 : :
14 : : /* Indicate AEQ_CTRL_0 shift. */
15 : : #define AEQ_CTRL_0_INTR_IDX_SHIFT 0
16 : : #define AEQ_CTRL_0_DMA_ATTR_SHIFT 12
17 : : #define AEQ_CTRL_0_PCI_INTF_IDX_SHIFT 20
18 : : #define AEQ_CTRL_0_INTR_MODE_SHIFT 31
19 : :
20 : : /* Indicate AEQ_CTRL_0 mask. */
21 : : #define AEQ_CTRL_0_INTR_IDX_MASK 0x3FFU
22 : : #define AEQ_CTRL_0_DMA_ATTR_MASK 0x3FU
23 : : #define AEQ_CTRL_0_PCI_INTF_IDX_MASK 0x7U
24 : : #define AEQ_CTRL_0_INTR_MODE_MASK 0x1U
25 : :
26 : : /* Set and clear the AEQ_CTRL_0 bit fields. */
27 : : #define AEQ_CTRL_0_SET(val, member) \
28 : : (((val) & AEQ_CTRL_0_##member##_MASK) << AEQ_CTRL_0_##member##_SHIFT)
29 : : #define AEQ_CTRL_0_CLEAR(val, member) \
30 : : ((val) & (~(AEQ_CTRL_0_##member##_MASK << AEQ_CTRL_0_##member##_SHIFT)))
31 : :
32 : : /* Indicate AEQ_CTRL_1 shift. */
33 : : #define AEQ_CTRL_1_LEN_SHIFT 0
34 : : #define AEQ_CTRL_1_ELEM_SIZE_SHIFT 24
35 : : #define AEQ_CTRL_1_PAGE_SIZE_SHIFT 28
36 : :
37 : : /* Indicate AEQ_CTRL_1 mask. */
38 : : #define AEQ_CTRL_1_LEN_MASK 0x1FFFFFU
39 : : #define AEQ_CTRL_1_ELEM_SIZE_MASK 0x3U
40 : : #define AEQ_CTRL_1_PAGE_SIZE_MASK 0xFU
41 : :
42 : : /* Set and clear the AEQ_CTRL_1 bit fields. */
43 : : #define AEQ_CTRL_1_SET(val, member) \
44 : : (((val) & AEQ_CTRL_1_##member##_MASK) << AEQ_CTRL_1_##member##_SHIFT)
45 : : #define AEQ_CTRL_1_CLEAR(val, member) \
46 : : ((val) & (~(AEQ_CTRL_1_##member##_MASK << AEQ_CTRL_1_##member##_SHIFT)))
47 : :
48 : : #define HINIC3_EQ_UPDATE_CI_STEP 64
49 : :
50 : : /* Indicate EQ_ELEM_DESC shift. */
51 : : #define EQ_ELEM_DESC_TYPE_SHIFT 0
52 : : #define EQ_ELEM_DESC_SRC_SHIFT 7
53 : : #define EQ_ELEM_DESC_SIZE_SHIFT 8
54 : : #define EQ_ELEM_DESC_WRAPPED_SHIFT 31
55 : :
56 : : /* Indicate EQ_ELEM_DESC mask. */
57 : : #define EQ_ELEM_DESC_TYPE_MASK 0x7FU
58 : : #define EQ_ELEM_DESC_SRC_MASK 0x1U
59 : : #define EQ_ELEM_DESC_SIZE_MASK 0xFFU
60 : : #define EQ_ELEM_DESC_WRAPPED_MASK 0x1U
61 : :
62 : : /* Get the AEQ_CTRL_1 bit fields. */
63 : : #define EQ_ELEM_DESC_GET(val, member) \
64 : : (((val) >> EQ_ELEM_DESC_##member##_SHIFT) & \
65 : : EQ_ELEM_DESC_##member##_MASK)
66 : :
67 : : /* Indicate EQ_CI_SIMPLE_INDIR shift. */
68 : : #define EQ_CI_SIMPLE_INDIR_CI_SHIFT 0
69 : : #define EQ_CI_SIMPLE_INDIR_ARMED_SHIFT 21
70 : : #define EQ_CI_SIMPLE_INDIR_AEQ_IDX_SHIFT 30
71 : :
72 : : /* Indicate EQ_CI_SIMPLE_INDIR mask. */
73 : : #define EQ_CI_SIMPLE_INDIR_CI_MASK 0x1FFFFFU
74 : : #define EQ_CI_SIMPLE_INDIR_ARMED_MASK 0x1U
75 : : #define EQ_CI_SIMPLE_INDIR_AEQ_IDX_MASK 0x3U
76 : :
77 : : /* Set and clear the EQ_CI_SIMPLE_INDIR bit fields. */
78 : : #define EQ_CI_SIMPLE_INDIR_SET(val, member) \
79 : : (((val) & EQ_CI_SIMPLE_INDIR_##member##_MASK) \
80 : : << EQ_CI_SIMPLE_INDIR_##member##_SHIFT)
81 : : #define EQ_CI_SIMPLE_INDIR_CLEAR(val, member) \
82 : : ((val) & (~(EQ_CI_SIMPLE_INDIR_##member##_MASK \
83 : : << EQ_CI_SIMPLE_INDIR_##member##_SHIFT)))
84 : :
85 : : #define EQ_WRAPPED(eq) ((uint32_t)(eq)->wrapped << EQ_VALID_SHIFT)
86 : :
87 : : #define EQ_CONS_IDX(eq) \
88 : : ({ \
89 : : typeof(eq) __eq = (eq); \
90 : : __eq->cons_idx | ((uint32_t)__eq->wrapped << EQ_WRAPPED_SHIFT); \
91 : : })
92 : : #define GET_EQ_NUM_PAGES(eq, size) \
93 : : ({ \
94 : : typeof(eq) __eq = (eq); \
95 : : typeof(size) __size = (size); \
96 : : (uint16_t)(RTE_ALIGN((uint32_t)(__eq->eq_len * __eq->elem_size), \
97 : : __size) / \
98 : : __size); \
99 : : })
100 : :
101 : : #define GET_EQ_NUM_ELEMS(eq, pg_size) ((pg_size) / (uint32_t)(eq)->elem_size)
102 : :
103 : : #define GET_EQ_ELEMENT(eq, idx) \
104 : : ({ \
105 : : typeof(eq) __eq = (eq); \
106 : : typeof(idx) __idx = (idx); \
107 : : ((uint8_t *)__eq->virt_addr[__idx / __eq->num_elem_in_pg]) + \
108 : : (uint32_t)((__idx & (__eq->num_elem_in_pg - 1)) * \
109 : : __eq->elem_size); \
110 : : })
111 : :
112 : : #define GET_AEQ_ELEM(eq, idx) \
113 : : ((struct hinic3_aeq_elem *)GET_EQ_ELEMENT((eq), (idx)))
114 : :
115 : : #define PAGE_IN_4K(page_size) ((page_size) >> 12)
116 : : #define EQ_SET_HW_PAGE_SIZE_VAL(eq) ((uint32_t)rte_log2_u32(PAGE_IN_4K((eq)->page_size)))
117 : :
118 : : #define ELEMENT_SIZE_IN_32B(eq) (((eq)->elem_size) >> 5)
119 : : #define EQ_SET_HW_ELEM_SIZE_VAL(eq) ((uint32_t)rte_log2_u32(ELEMENT_SIZE_IN_32B(eq)))
120 : :
121 : : #define AEQ_DMA_ATTR_DEFAULT 0
122 : :
123 : : #define EQ_WRAPPED_SHIFT 20
124 : :
125 : : #define EQ_VALID_SHIFT 31
126 : :
127 : : #define aeq_to_aeqs(eq) \
128 : : ({ \
129 : : typeof(eq) __eq = (eq); \
130 : : container_of(__eq - __eq->q_id, struct hinic3_aeqs, aeq[0]); \
131 : : })
132 : :
133 : : #define AEQ_MSIX_ENTRY_IDX_0 0
134 : :
135 : : /**
136 : : * Write the consumer idx to hw.
137 : : *
138 : : * @param[in] eq
139 : : * The event queue to update the cons idx.
140 : : * @param[in] arm_state
141 : : * Indicate whether report interrupts when generate eq element.
142 : : */
143 : : static void
144 : 0 : set_eq_cons_idx(struct hinic3_eq *eq, uint32_t arm_state)
145 : : {
146 : : uint32_t eq_wrap_ci = 0;
147 : : uint32_t val = 0;
148 : : uint32_t addr = HINIC3_CSR_AEQ_CI_SIMPLE_INDIR_ADDR;
149 : :
150 : 0 : eq_wrap_ci = EQ_CONS_IDX(eq);
151 : :
152 [ # # ]: 0 : if (eq->q_id != 0)
153 : : val = EQ_CI_SIMPLE_INDIR_SET(HINIC3_EQ_NOT_ARMED, ARMED);
154 : : else
155 : 0 : val = EQ_CI_SIMPLE_INDIR_SET(arm_state, ARMED);
156 : :
157 : 0 : val = val | EQ_CI_SIMPLE_INDIR_SET(eq_wrap_ci, CI) |
158 : 0 : EQ_CI_SIMPLE_INDIR_SET(eq->q_id, AEQ_IDX);
159 : :
160 : 0 : hinic3_hwif_write_reg(eq->hwdev->hwif, addr, val);
161 : 0 : }
162 : :
163 : : /**
164 : : * Set aeq's ctrls registers.
165 : : *
166 : : * @param[in] eq
167 : : * The event queue for setting.
168 : : */
169 : : static void
170 : 0 : set_aeq_ctrls(struct hinic3_eq *eq)
171 : : {
172 : 0 : struct hinic3_hwif *hwif = eq->hwdev->hwif;
173 : : struct irq_info *eq_irq = &eq->eq_irq;
174 : : uint32_t addr, val, ctrl0, ctrl1, page_size_val, elem_size;
175 : 0 : uint32_t pci_intf_idx = HINIC3_PCI_INTF_IDX(hwif);
176 : :
177 : : /* Set AEQ ctrl0. */
178 : : addr = HINIC3_CSR_AEQ_CTRL_0_ADDR;
179 : :
180 : 0 : val = hinic3_hwif_read_reg(hwif, addr);
181 : :
182 : 0 : val = AEQ_CTRL_0_CLEAR(val, INTR_IDX) &
183 : : AEQ_CTRL_0_CLEAR(val, DMA_ATTR) &
184 : : AEQ_CTRL_0_CLEAR(val, PCI_INTF_IDX) &
185 : : AEQ_CTRL_0_CLEAR(val, INTR_MODE);
186 : :
187 : 0 : ctrl0 = AEQ_CTRL_0_SET(eq_irq->msix_entry_idx, INTR_IDX) |
188 : : AEQ_CTRL_0_SET(AEQ_DMA_ATTR_DEFAULT, DMA_ATTR) |
189 : 0 : AEQ_CTRL_0_SET(pci_intf_idx, PCI_INTF_IDX) |
190 : : AEQ_CTRL_0_SET(HINIC3_INTR_MODE_ARMED, INTR_MODE);
191 : :
192 : 0 : val |= ctrl0;
193 : :
194 : 0 : hinic3_hwif_write_reg(hwif, addr, val);
195 : :
196 : : /* Set AEQ ctrl1. */
197 : : addr = HINIC3_CSR_AEQ_CTRL_1_ADDR;
198 : :
199 [ # # ]: 0 : page_size_val = EQ_SET_HW_PAGE_SIZE_VAL(eq);
200 [ # # ]: 0 : elem_size = EQ_SET_HW_ELEM_SIZE_VAL(eq);
201 : :
202 : 0 : ctrl1 = AEQ_CTRL_1_SET(eq->eq_len, LEN) |
203 : 0 : AEQ_CTRL_1_SET(elem_size, ELEM_SIZE) |
204 : 0 : AEQ_CTRL_1_SET(page_size_val, PAGE_SIZE);
205 : :
206 : 0 : hinic3_hwif_write_reg(hwif, addr, ctrl1);
207 : 0 : }
208 : :
209 : : /**
210 : : * Initialize all the elements in the aeq.
211 : : *
212 : : * @param[in] eq
213 : : * The event queue.
214 : : * @param[in] init_val
215 : : * Value to init.
216 : : */
217 : : static void
218 : 0 : aeq_elements_init(struct hinic3_eq *eq)
219 : : {
220 : : struct hinic3_aeq_elem *aeqe = NULL;
221 : : uint32_t i;
222 : :
223 [ # # ]: 0 : for (i = 0; i < eq->eq_len; i++) {
224 : 0 : aeqe = GET_AEQ_ELEM(eq, i);
225 [ # # ]: 0 : aeqe->desc = rte_cpu_to_be_32(EQ_WRAPPED(eq));
226 : : }
227 : :
228 : : rte_atomic_thread_fence(rte_memory_order_release); /**< Write the init values. */
229 : 0 : }
230 : :
231 : : /**
232 : : * Set the pages for the event queue.
233 : : *
234 : : * @param[in] eq
235 : : * The event queue.
236 : : * @return
237 : : * 0 on success, non-zero on failure.
238 : : */
239 : : static int
240 : 0 : set_eq_pages(struct hinic3_eq *eq)
241 : : {
242 : 0 : struct hinic3_hwif *hwif = eq->hwdev->hwif;
243 : : uint32_t reg;
244 : : uint16_t pg_num, i;
245 : : int err;
246 : :
247 [ # # ]: 0 : for (pg_num = 0; pg_num < eq->num_pages; pg_num++) {
248 : : /* Allocate memory for each page. */
249 : 0 : eq->eq_mz[pg_num] = hinic3_dma_zone_reserve(eq->hwdev->eth_dev,
250 : 0 : "eq_mz", eq->q_id, eq->page_size,
251 : : eq->page_size, SOCKET_ID_ANY);
252 [ # # ]: 0 : if (!eq->eq_mz[pg_num]) {
253 : : err = -ENOMEM;
254 : 0 : goto dma_alloc_err;
255 : : }
256 : :
257 : : /* Write physical memory address and virtual memory address. */
258 : 0 : eq->dma_addr[pg_num] = eq->eq_mz[pg_num]->iova;
259 : 0 : eq->virt_addr[pg_num] = eq->eq_mz[pg_num]->addr;
260 : :
261 : 0 : reg = HINIC3_AEQ_HI_PHYS_ADDR_REG(pg_num);
262 : 0 : hinic3_hwif_write_reg(hwif, reg,
263 : 0 : upper_32_bits(eq->dma_addr[pg_num]));
264 : :
265 : 0 : reg = HINIC3_AEQ_LO_PHYS_ADDR_REG(pg_num);
266 : 0 : hinic3_hwif_write_reg(hwif, reg,
267 : 0 : lower_32_bits(eq->dma_addr[pg_num]));
268 : : }
269 : : /* Calculate the number of elements that can be accommodated. */
270 : 0 : eq->num_elem_in_pg = GET_EQ_NUM_ELEMS(eq, eq->page_size);
271 [ # # ]: 0 : if (eq->num_elem_in_pg & (eq->num_elem_in_pg - 1)) {
272 : 0 : PMD_DRV_LOG(ERR, "Number element in eq page != power of 2");
273 : : err = -EINVAL;
274 : 0 : goto dma_alloc_err;
275 : : }
276 : : /* Initialize elements in the queue. */
277 : 0 : aeq_elements_init(eq);
278 : :
279 : 0 : return 0;
280 : :
281 : 0 : dma_alloc_err:
282 [ # # ]: 0 : for (i = 0; i < pg_num; i++)
283 : 0 : hinic3_memzone_free(eq->eq_mz[i]);
284 : :
285 : : return err;
286 : : }
287 : :
288 : : /**
289 : : * Allocate the pages for the event queue.
290 : : *
291 : : * @param[in] eq
292 : : * The event queue.
293 : : * @return
294 : : * 0 on success, non-zero on failure.
295 : : */
296 : : static int
297 : 0 : alloc_eq_pages(struct hinic3_eq *eq)
298 : : {
299 : : uint64_t dma_addr_size, virt_addr_size, eq_mz_size;
300 : : int err;
301 : :
302 : : /* Calculate the size of the memory to be allocated. */
303 : 0 : dma_addr_size = eq->num_pages * sizeof(*eq->dma_addr);
304 : : virt_addr_size = eq->num_pages * sizeof(*eq->virt_addr);
305 : : eq_mz_size = eq->num_pages * sizeof(*eq->eq_mz);
306 : :
307 : 0 : eq->dma_addr =
308 : 0 : rte_zmalloc("eq_dma", dma_addr_size, HINIC3_MEM_ALLOC_ALIGN_MIN);
309 [ # # ]: 0 : if (!eq->dma_addr)
310 : : return -ENOMEM;
311 : :
312 : 0 : eq->virt_addr =
313 : 0 : rte_zmalloc("eq_va", virt_addr_size, HINIC3_MEM_ALLOC_ALIGN_MIN);
314 [ # # ]: 0 : if (!eq->virt_addr) {
315 : : err = -ENOMEM;
316 : 0 : goto virt_addr_alloc_err;
317 : : }
318 : :
319 : 0 : eq->eq_mz =
320 : 0 : rte_zmalloc("eq_mz", eq_mz_size, HINIC3_MEM_ALLOC_ALIGN_MIN);
321 [ # # ]: 0 : if (!eq->eq_mz) {
322 : : err = -ENOMEM;
323 : 0 : goto eq_mz_alloc_err;
324 : : }
325 : 0 : err = set_eq_pages(eq);
326 [ # # ]: 0 : if (err)
327 : 0 : goto eq_pages_err;
328 : :
329 : : return 0;
330 : :
331 : : eq_pages_err:
332 : 0 : rte_free(eq->eq_mz);
333 : :
334 : 0 : eq_mz_alloc_err:
335 : 0 : rte_free(eq->virt_addr);
336 : :
337 : 0 : virt_addr_alloc_err:
338 : 0 : rte_free(eq->dma_addr);
339 : :
340 : 0 : return err;
341 : : }
342 : :
343 : : /**
344 : : * Free the pages of the event queue.
345 : : *
346 : : * @param[in] eq
347 : : * The event queue.
348 : : */
349 : : static void
350 : 0 : free_eq_pages(struct hinic3_eq *eq)
351 : : {
352 : : uint16_t pg_num;
353 : :
354 [ # # ]: 0 : for (pg_num = 0; pg_num < eq->num_pages; pg_num++)
355 : 0 : hinic3_memzone_free(eq->eq_mz[pg_num]);
356 : :
357 : 0 : rte_free(eq->eq_mz);
358 : 0 : rte_free(eq->virt_addr);
359 : 0 : rte_free(eq->dma_addr);
360 : 0 : }
361 : :
362 : : static uint32_t
363 : : get_page_size(struct hinic3_eq *eq)
364 : : {
365 : : uint32_t total_size;
366 : : uint16_t count;
367 : :
368 : : /* Total memory size. */
369 : 0 : total_size = RTE_ALIGN((eq->eq_len * eq->elem_size), HINIC3_MIN_EQ_PAGE_SIZE);
370 : 0 : if (total_size <= (HINIC3_EQ_MAX_PAGES * HINIC3_MIN_EQ_PAGE_SIZE))
371 : : return HINIC3_MIN_EQ_PAGE_SIZE;
372 : : /* Total number of pages. */
373 : 0 : count = (uint16_t)(RTE_ALIGN((total_size / HINIC3_EQ_MAX_PAGES),
374 : 0 : HINIC3_MIN_EQ_PAGE_SIZE) /
375 : : HINIC3_MIN_EQ_PAGE_SIZE);
376 : :
377 : : /* Whether count is a power of 2. */
378 [ # # ]: 0 : if (!(count & (count - 1)))
379 : 0 : return HINIC3_MIN_EQ_PAGE_SIZE * count;
380 : :
381 : 0 : return ((uint32_t)HINIC3_MIN_EQ_PAGE_SIZE) << rte_ctz32(count);
382 : : }
383 : :
384 : : /**
385 : : * Initialize AEQ.
386 : : *
387 : : * @param[in] eq
388 : : * The event queue.
389 : : * @param[in] hwdev
390 : : * The pointer to the private hardware device.
391 : : * @param[in] q_id
392 : : * Queue id number.
393 : : * @param[in] q_len
394 : : * The number of EQ elements.
395 : : * @return
396 : : * 0 on success, non-zero on failure.
397 : : */
398 : : static int
399 : 0 : init_aeq(struct hinic3_eq *eq, struct hinic3_hwdev *hwdev, uint16_t q_id, uint32_t q_len)
400 : : {
401 : : int err = 0;
402 : :
403 : 0 : eq->hwdev = hwdev;
404 : 0 : eq->q_id = q_id;
405 : 0 : eq->eq_len = q_len;
406 : :
407 : : /* Indirect access should set q_id first. */
408 : 0 : hinic3_hwif_write_reg(hwdev->hwif, HINIC3_AEQ_INDIR_IDX_ADDR, eq->q_id);
409 : : rte_atomic_thread_fence(rte_memory_order_release); /**< write index before config. */
410 : :
411 : : /* Clear eq_len to force eqe drop in hardware. */
412 : 0 : hinic3_hwif_write_reg(eq->hwdev->hwif, HINIC3_CSR_AEQ_CTRL_1_ADDR, 0);
413 : : rte_atomic_thread_fence(rte_memory_order_release);
414 : : /* Init aeq pi to 0 before allocating aeq pages. */
415 : 0 : hinic3_hwif_write_reg(eq->hwdev->hwif, HINIC3_CSR_AEQ_PROD_IDX_ADDR, 0);
416 : :
417 : 0 : eq->cons_idx = 0;
418 : 0 : eq->wrapped = 0;
419 : :
420 [ # # ]: 0 : eq->elem_size = HINIC3_AEQE_SIZE;
421 : 0 : eq->page_size = get_page_size(eq);
422 : 0 : eq->orig_page_size = eq->page_size;
423 : 0 : eq->num_pages = GET_EQ_NUM_PAGES(eq, eq->page_size);
424 [ # # ]: 0 : if (eq->num_pages > HINIC3_EQ_MAX_PAGES) {
425 : 0 : PMD_DRV_LOG(ERR, "Too many pages: %d for aeq", eq->num_pages);
426 : 0 : return -EINVAL;
427 : : }
428 : :
429 : 0 : err = alloc_eq_pages(eq);
430 [ # # ]: 0 : if (err) {
431 : 0 : PMD_DRV_LOG(ERR, "Allocate pages for eq failed");
432 : 0 : return err;
433 : : }
434 : :
435 : : /* Pmd driver uses AEQ_MSIX_ENTRY_IDX_0. */
436 : 0 : eq->eq_irq.msix_entry_idx = AEQ_MSIX_ENTRY_IDX_0;
437 : 0 : set_aeq_ctrls(eq);
438 : :
439 : 0 : set_eq_cons_idx(eq, HINIC3_EQ_ARMED);
440 : :
441 [ # # ]: 0 : if (eq->q_id == 0)
442 : 0 : hinic3_set_msix_state(hwdev, 0, HINIC3_MSIX_ENABLE);
443 : :
444 : 0 : eq->poll_retry_nr = HINIC3_RETRY_NUM;
445 : :
446 : 0 : return 0;
447 : : }
448 : :
449 : : /**
450 : : * Remove AEQ.
451 : : *
452 : : * @param[in] eq
453 : : * The event queue.
454 : : */
455 : : static void
456 : 0 : remove_aeq(struct hinic3_eq *eq)
457 : : {
458 : : struct irq_info *entry = &eq->eq_irq;
459 : :
460 [ # # ]: 0 : if (eq->q_id == 0)
461 : 0 : hinic3_set_msix_state(eq->hwdev, entry->msix_entry_idx,
462 : : HINIC3_MSIX_DISABLE);
463 : :
464 : : /* Indirect access should set q_id first. */
465 : 0 : hinic3_hwif_write_reg(eq->hwdev->hwif, HINIC3_AEQ_INDIR_IDX_ADDR, eq->q_id);
466 : :
467 : : rte_atomic_thread_fence(rte_memory_order_release); /**< Write index before config. */
468 : :
469 : : /* Clear eq_len to avoid hw access host memory. */
470 : 0 : hinic3_hwif_write_reg(eq->hwdev->hwif, HINIC3_CSR_AEQ_CTRL_1_ADDR, 0);
471 : :
472 : : /* Update cons_idx to avoid invalid interrupt. */
473 : 0 : eq->cons_idx = hinic3_hwif_read_reg(eq->hwdev->hwif,
474 : : HINIC3_CSR_AEQ_PROD_IDX_ADDR);
475 : 0 : set_eq_cons_idx(eq, HINIC3_EQ_NOT_ARMED);
476 : :
477 : 0 : free_eq_pages(eq);
478 : 0 : }
479 : :
480 : : /**
481 : : * Init all AEQs.
482 : : *
483 : : * @param[in] hwdev
484 : : * The pointer to the private hardware device object
485 : : * @return
486 : : * 0 on success, non-zero on failure.
487 : : */
488 : : int
489 : 0 : hinic3_aeqs_init(struct hinic3_hwdev *hwdev)
490 : : {
491 : : struct hinic3_aeqs *aeqs = NULL;
492 : : uint16_t num_aeqs;
493 : : int err;
494 : : uint16_t i, q_id;
495 : :
496 [ # # ]: 0 : if (!hwdev)
497 : : return -EINVAL;
498 : :
499 : 0 : num_aeqs = HINIC3_HWIF_NUM_AEQS(hwdev->hwif);
500 [ # # ]: 0 : if (num_aeqs > HINIC3_MAX_AEQS) {
501 : 0 : PMD_DRV_LOG(INFO, "Adjust aeq num to %d", HINIC3_MAX_AEQS);
502 : : num_aeqs = HINIC3_MAX_AEQS;
503 [ # # ]: 0 : } else if (num_aeqs < HINIC3_MIN_AEQS) {
504 : 0 : PMD_DRV_LOG(ERR, "PMD needs %d AEQs, Chip has %d",
505 : : HINIC3_MIN_AEQS, num_aeqs);
506 : 0 : return -EINVAL;
507 : : }
508 : :
509 : 0 : aeqs = rte_zmalloc("hinic3_aeqs", sizeof(*aeqs),
510 : : HINIC3_MEM_ALLOC_ALIGN_MIN);
511 [ # # ]: 0 : if (!aeqs)
512 : : return -ENOMEM;
513 : :
514 : 0 : hwdev->aeqs = aeqs;
515 : 0 : aeqs->hwdev = hwdev;
516 : 0 : aeqs->num_aeqs = num_aeqs;
517 : :
518 [ # # ]: 0 : for (q_id = 0; q_id < num_aeqs; q_id++) {
519 : 0 : err = init_aeq(&aeqs->aeq[q_id], hwdev, q_id,
520 : : HINIC3_DEFAULT_AEQ_LEN);
521 [ # # ]: 0 : if (err) {
522 : 0 : PMD_DRV_LOG(ERR, "Init aeq %d failed", q_id);
523 : 0 : goto init_aeq_err;
524 : : }
525 : : }
526 : :
527 : : return 0;
528 : :
529 : : init_aeq_err:
530 [ # # ]: 0 : for (i = 0; i < q_id; i++)
531 : 0 : remove_aeq(&aeqs->aeq[i]);
532 : :
533 : 0 : rte_free(aeqs);
534 : 0 : return err;
535 : : }
536 : :
537 : : /**
538 : : * Free all AEQs.
539 : : *
540 : : * @param[in] hwdev
541 : : * The pointer to the private hardware device.
542 : : */
543 : : void
544 : 0 : hinic3_aeqs_free(struct hinic3_hwdev *hwdev)
545 : : {
546 : 0 : struct hinic3_aeqs *aeqs = hwdev->aeqs;
547 : : uint16_t q_id;
548 : :
549 [ # # ]: 0 : for (q_id = 0; q_id < aeqs->num_aeqs; q_id++)
550 : 0 : remove_aeq(&aeqs->aeq[q_id]);
551 : :
552 : 0 : rte_free(aeqs);
553 : 0 : }
554 : :
555 : : void
556 : 0 : hinic3_dump_aeq_info(struct hinic3_hwdev *hwdev)
557 : : {
558 : : struct hinic3_aeq_elem *aeqe_pos = NULL;
559 : : struct hinic3_eq *eq = NULL;
560 : : uint32_t addr, ci, pi, ctrl0, idx;
561 : : int q_id;
562 : :
563 [ # # ]: 0 : for (q_id = 0; q_id < hwdev->aeqs->num_aeqs; q_id++) {
564 : : eq = &hwdev->aeqs->aeq[q_id];
565 : : /* Indirect access should set q_id first. */
566 : 0 : hinic3_hwif_write_reg(eq->hwdev->hwif,
567 : 0 : HINIC3_AEQ_INDIR_IDX_ADDR, eq->q_id);
568 : : /* Write index before config. */
569 : : rte_atomic_thread_fence(rte_memory_order_release);
570 : :
571 : : addr = HINIC3_CSR_AEQ_CTRL_0_ADDR;
572 : :
573 : 0 : ctrl0 = hinic3_hwif_read_reg(hwdev->hwif, addr);
574 : :
575 : 0 : idx = hinic3_hwif_read_reg(hwdev->hwif,
576 : : HINIC3_AEQ_INDIR_IDX_ADDR);
577 : :
578 : : addr = HINIC3_CSR_AEQ_CONS_IDX_ADDR;
579 : 0 : ci = hinic3_hwif_read_reg(hwdev->hwif, addr);
580 : : addr = HINIC3_CSR_AEQ_PROD_IDX_ADDR;
581 : 0 : pi = hinic3_hwif_read_reg(hwdev->hwif, addr);
582 : 0 : aeqe_pos = GET_AEQ_ELEM(eq, eq->cons_idx);
583 [ # # ]: 0 : PMD_DRV_LOG(ERR,
584 : : "Aeq id: %d, idx: %u, ctrl0: 0x%08x, wrap: %d, pi: 0x%x, ci: 0x%08x, desc: 0x%x",
585 : : q_id, idx, ctrl0, eq->wrapped, pi, ci,
586 : : rte_be_to_cpu_32(aeqe_pos->desc));
587 : : }
588 : 0 : }
589 : :
590 : : static int
591 : 0 : aeq_elem_handler(struct hinic3_eq *eq, uint32_t aeqe_desc,
592 : : struct hinic3_aeq_elem *aeqe_pos, void *param)
593 : : {
594 : : enum hinic3_aeq_type event;
595 : : uint8_t data[HINIC3_AEQE_DATA_SIZE];
596 : : uint8_t size;
597 : :
598 : 0 : event = EQ_ELEM_DESC_GET(aeqe_desc, TYPE);
599 [ # # ]: 0 : if (EQ_ELEM_DESC_GET(aeqe_desc, SRC)) {
600 : : /* SW event uses only the first 8B. */
601 : : memcpy(data, aeqe_pos->aeqe_data, HINIC3_AEQE_DATA_SIZE);
602 : : hinic3_be32_to_cpu(data, HINIC3_AEQE_DATA_SIZE);
603 : : /* Just support HINIC3_STATELESS_EVENT. */
604 : 0 : return hinic3_nic_sw_aeqe_handler(eq->hwdev, event, data);
605 : : }
606 : :
607 : : memcpy(data, aeqe_pos->aeqe_data, HINIC3_AEQE_DATA_SIZE);
608 : : hinic3_be32_to_cpu(data, HINIC3_AEQE_DATA_SIZE);
609 : 0 : size = EQ_ELEM_DESC_GET(aeqe_desc, SIZE);
610 : :
611 [ # # ]: 0 : if (event == HINIC3_MSG_FROM_MGMT_CPU)
612 : 0 : return hinic3_mgmt_msg_aeqe_handler(eq->hwdev, data, size, param);
613 [ # # ]: 0 : else if (event == HINIC3_MBX_FROM_FUNC)
614 : 0 : return hinic3_mbox_func_aeqe_handler(eq->hwdev, data, size, param);
615 : 0 : PMD_DRV_LOG(ERR, "AEQ hw event not support %d", event);
616 : 0 : return -EINVAL;
617 : : }
618 : :
619 : : /**
620 : : * Poll one or continue aeqe, and call dedicated process.
621 : : *
622 : : * @param[in] eq
623 : : * Pointer to the event queue.
624 : : * @param[in] timeout
625 : : * equal to 0 - Poll all aeqe in eq, used in interrupt mode.
626 : : * Greater than 0 - Poll aeq until get aeqe with 'last' field set to 1, used in
627 : : * polling mode.
628 : : * @param[in] param
629 : : * Customized parameter.
630 : : * @return
631 : : * 0 on success, non-zero on failure.
632 : : */
633 : : int
634 : 0 : hinic3_aeq_poll_msg(struct hinic3_eq *eq, uint32_t timeout, void *param)
635 : : {
636 : : struct hinic3_aeq_elem *aeqe_pos = NULL;
637 : : uint32_t aeqe_desc = 0;
638 : : uint32_t eqe_cnt = 0;
639 : : int err = -EFAULT;
640 : : int done = HINIC3_MSG_HANDLER_RES;
641 : : uint64_t end;
642 : : uint16_t i;
643 : :
644 [ # # # # ]: 0 : for (i = 0; ((timeout == 0) && (i < eq->eq_len)) ||
645 [ # # ]: 0 : ((timeout > 0) && (done != 0) && (i < eq->eq_len));
646 : 0 : i++) {
647 : : err = -EIO;
648 : 0 : end = cycles + msecs_to_cycles(timeout);
649 : : do {
650 : 0 : aeqe_pos = GET_AEQ_ELEM(eq, eq->cons_idx);
651 : :
652 : : /* Data in HW is in Big endian format. */
653 [ # # ]: 0 : aeqe_desc = rte_be_to_cpu_32(aeqe_pos->desc);
654 : :
655 : : /*
656 : : * HW updates wrapped bit, when it adds eq element
657 : : * event.
658 : : */
659 [ # # ]: 0 : if (EQ_ELEM_DESC_GET(aeqe_desc, WRAPPED) != eq->wrapped) {
660 : : err = 0;
661 : : /*
662 : : * Barrier is to prevent the CPU from loading the
663 : : * wrong memory content before HW updating wrapped bit
664 : : */
665 : : rte_atomic_thread_fence(rte_memory_order_acquire);
666 : : break;
667 : : }
668 : :
669 [ # # ]: 0 : if (timeout != 0)
670 : 0 : usleep(HINIC3_AEQE_DESC_SIZE);
671 [ # # ]: 0 : } while (time_before(cycles, end));
672 : :
673 : : if (err) /**< Poll time out. */
674 : : break;
675 : : /* Handle the middle element of the event queue. */
676 : 0 : done = aeq_elem_handler(eq, aeqe_desc, aeqe_pos, param);
677 : :
678 : 0 : eq->cons_idx++;
679 [ # # ]: 0 : if (eq->cons_idx == eq->eq_len) {
680 : 0 : eq->cons_idx = 0;
681 : 0 : eq->wrapped = !eq->wrapped;
682 : : }
683 : :
684 [ # # ]: 0 : if (++eqe_cnt >= HINIC3_EQ_UPDATE_CI_STEP) {
685 : : eqe_cnt = 0;
686 : 0 : set_eq_cons_idx(eq, HINIC3_EQ_NOT_ARMED);
687 : : }
688 : : }
689 : : /* Set the consumer index of the event queue. */
690 : 0 : set_eq_cons_idx(eq, HINIC3_EQ_ARMED);
691 : :
692 : 0 : return err;
693 : : }
694 : :
695 : : void
696 : 0 : hinic3_dev_handle_aeq_event(struct hinic3_hwdev *hwdev, void *param)
697 : : {
698 : 0 : struct hinic3_eq *aeq = &hwdev->aeqs->aeq[0];
699 : :
700 : : /* Clear resend timer cnt register. */
701 : 0 : hinic3_misx_intr_clear_resend_bit(hwdev, aeq->eq_irq.msix_entry_idx,
702 : : MSIX_RESEND_TIMER_CLEAR);
703 : 0 : hinic3_aeq_poll_msg(aeq, 0, param);
704 : 0 : }
|