xref: /dpdk/drivers/net/hinic/base/hinic_pmd_eqs.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
178f6c5dbSZiyang Xuan /* SPDX-License-Identifier: BSD-3-Clause
278f6c5dbSZiyang Xuan  * Copyright(c) 2017 Huawei Technologies Co., Ltd
378f6c5dbSZiyang Xuan  */
478f6c5dbSZiyang Xuan 
578f6c5dbSZiyang Xuan #include "hinic_compat.h"
678f6c5dbSZiyang Xuan #include "hinic_csr.h"
778f6c5dbSZiyang Xuan #include "hinic_pmd_hwdev.h"
878f6c5dbSZiyang Xuan #include "hinic_pmd_hwif.h"
978f6c5dbSZiyang Xuan #include "hinic_pmd_mgmt.h"
1078f6c5dbSZiyang Xuan #include "hinic_pmd_eqs.h"
1178f6c5dbSZiyang Xuan 
1278f6c5dbSZiyang Xuan #define AEQ_CTRL_0_INTR_IDX_SHIFT		0
1378f6c5dbSZiyang Xuan #define AEQ_CTRL_0_DMA_ATTR_SHIFT		12
1478f6c5dbSZiyang Xuan #define AEQ_CTRL_0_PCI_INTF_IDX_SHIFT		20
1578f6c5dbSZiyang Xuan #define AEQ_CTRL_0_INTR_MODE_SHIFT		31
1678f6c5dbSZiyang Xuan 
1778f6c5dbSZiyang Xuan #define AEQ_CTRL_0_INTR_IDX_MASK		0x3FFU
1878f6c5dbSZiyang Xuan #define AEQ_CTRL_0_DMA_ATTR_MASK		0x3FU
1978f6c5dbSZiyang Xuan #define AEQ_CTRL_0_PCI_INTF_IDX_MASK		0x3U
2078f6c5dbSZiyang Xuan #define AEQ_CTRL_0_INTR_MODE_MASK		0x1U
2178f6c5dbSZiyang Xuan 
2278f6c5dbSZiyang Xuan #define AEQ_CTRL_0_SET(val, member)		\
2378f6c5dbSZiyang Xuan 				(((val) & AEQ_CTRL_0_##member##_MASK) << \
2478f6c5dbSZiyang Xuan 				AEQ_CTRL_0_##member##_SHIFT)
2578f6c5dbSZiyang Xuan 
2678f6c5dbSZiyang Xuan #define AEQ_CTRL_0_CLEAR(val, member)		\
2778f6c5dbSZiyang Xuan 				((val) & (~(AEQ_CTRL_0_##member##_MASK \
2878f6c5dbSZiyang Xuan 					<< AEQ_CTRL_0_##member##_SHIFT)))
2978f6c5dbSZiyang Xuan 
3078f6c5dbSZiyang Xuan #define AEQ_CTRL_1_LEN_SHIFT			0
3178f6c5dbSZiyang Xuan #define AEQ_CTRL_1_ELEM_SIZE_SHIFT		24
3278f6c5dbSZiyang Xuan #define AEQ_CTRL_1_PAGE_SIZE_SHIFT		28
3378f6c5dbSZiyang Xuan 
3478f6c5dbSZiyang Xuan #define AEQ_CTRL_1_LEN_MASK			0x1FFFFFU
3578f6c5dbSZiyang Xuan #define AEQ_CTRL_1_ELEM_SIZE_MASK		0x3U
3678f6c5dbSZiyang Xuan #define AEQ_CTRL_1_PAGE_SIZE_MASK		0xFU
3778f6c5dbSZiyang Xuan 
3878f6c5dbSZiyang Xuan #define AEQ_CTRL_1_SET(val, member)		\
3978f6c5dbSZiyang Xuan 				(((val) & AEQ_CTRL_1_##member##_MASK) << \
4078f6c5dbSZiyang Xuan 				AEQ_CTRL_1_##member##_SHIFT)
4178f6c5dbSZiyang Xuan 
4278f6c5dbSZiyang Xuan #define AEQ_CTRL_1_CLEAR(val, member)		\
4378f6c5dbSZiyang Xuan 				((val) & (~(AEQ_CTRL_1_##member##_MASK \
4478f6c5dbSZiyang Xuan 					<< AEQ_CTRL_1_##member##_SHIFT)))
4578f6c5dbSZiyang Xuan 
4678f6c5dbSZiyang Xuan #define EQ_CONS_IDX_CONS_IDX_SHIFT		0
4778f6c5dbSZiyang Xuan #define EQ_CONS_IDX_XOR_CHKSUM_SHIFT		24
4878f6c5dbSZiyang Xuan #define EQ_CONS_IDX_INT_ARMED_SHIFT		31
4978f6c5dbSZiyang Xuan 
5078f6c5dbSZiyang Xuan #define EQ_CONS_IDX_CONS_IDX_MASK		0x1FFFFFU
5178f6c5dbSZiyang Xuan #define EQ_CONS_IDX_XOR_CHKSUM_MASK		0xFU
5278f6c5dbSZiyang Xuan #define EQ_CONS_IDX_INT_ARMED_MASK		0x1U
5378f6c5dbSZiyang Xuan 
5478f6c5dbSZiyang Xuan #define EQ_CONS_IDX_SET(val, member)		\
5578f6c5dbSZiyang Xuan 				(((val) & EQ_CONS_IDX_##member##_MASK) << \
5678f6c5dbSZiyang Xuan 				EQ_CONS_IDX_##member##_SHIFT)
5778f6c5dbSZiyang Xuan 
5878f6c5dbSZiyang Xuan #define EQ_CONS_IDX_CLEAR(val, member)		\
5978f6c5dbSZiyang Xuan 				((val) & (~(EQ_CONS_IDX_##member##_MASK \
6078f6c5dbSZiyang Xuan 					<< EQ_CONS_IDX_##member##_SHIFT)))
6178f6c5dbSZiyang Xuan 
6278f6c5dbSZiyang Xuan #define EQ_WRAPPED(eq)			((u32)(eq)->wrapped << EQ_VALID_SHIFT)
6378f6c5dbSZiyang Xuan 
6478f6c5dbSZiyang Xuan #define EQ_CONS_IDX(eq)		((eq)->cons_idx | \
6578f6c5dbSZiyang Xuan 				((u32)(eq)->wrapped << EQ_WRAPPED_SHIFT))
6678f6c5dbSZiyang Xuan 
67dd93390eSXiaoyun Wang #define EQ_CONS_IDX_REG_ADDR(eq)	\
68dd93390eSXiaoyun Wang 				(HINIC_CSR_AEQ_CONS_IDX_ADDR((eq)->q_id))
6978f6c5dbSZiyang Xuan 
70dd93390eSXiaoyun Wang #define EQ_PROD_IDX_REG_ADDR(eq)	\
71dd93390eSXiaoyun Wang 				(HINIC_CSR_AEQ_PROD_IDX_ADDR((eq)->q_id))
7278f6c5dbSZiyang Xuan 
7378f6c5dbSZiyang Xuan #define GET_EQ_NUM_PAGES(eq, size)		\
7478f6c5dbSZiyang Xuan 		((u16)(ALIGN((eq)->eq_len * (u32)(eq)->elem_size, (size)) \
7578f6c5dbSZiyang Xuan 		/ (size)))
7678f6c5dbSZiyang Xuan 
7778f6c5dbSZiyang Xuan #define GET_EQ_NUM_ELEMS(eq, pg_size)	((pg_size) / (u32)(eq)->elem_size)
7878f6c5dbSZiyang Xuan 
7978f6c5dbSZiyang Xuan #define PAGE_IN_4K(page_size)		((page_size) >> 12)
8078f6c5dbSZiyang Xuan #define EQ_SET_HW_PAGE_SIZE_VAL(eq) ((u32)ilog2(PAGE_IN_4K((eq)->page_size)))
8178f6c5dbSZiyang Xuan 
8278f6c5dbSZiyang Xuan #define ELEMENT_SIZE_IN_32B(eq)		(((eq)->elem_size) >> 5)
8378f6c5dbSZiyang Xuan #define EQ_SET_HW_ELEM_SIZE_VAL(eq)	((u32)ilog2(ELEMENT_SIZE_IN_32B(eq)))
8478f6c5dbSZiyang Xuan 
8578f6c5dbSZiyang Xuan #define AEQ_DMA_ATTR_DEFAULT			0
8678f6c5dbSZiyang Xuan 
8778f6c5dbSZiyang Xuan #define EQ_WRAPPED_SHIFT			20
8878f6c5dbSZiyang Xuan 
8978f6c5dbSZiyang Xuan #define	EQ_VALID_SHIFT				31
9078f6c5dbSZiyang Xuan 
9178f6c5dbSZiyang Xuan #define aeq_to_aeqs(eq) \
9278f6c5dbSZiyang Xuan 		container_of((eq) - (eq)->q_id, struct hinic_aeqs, aeq[0])
9378f6c5dbSZiyang Xuan 
9478f6c5dbSZiyang Xuan static u8 eq_cons_idx_checksum_set(u32 val)
9578f6c5dbSZiyang Xuan {
9678f6c5dbSZiyang Xuan 	u8 checksum = 0;
9778f6c5dbSZiyang Xuan 	u8 idx;
9878f6c5dbSZiyang Xuan 
9978f6c5dbSZiyang Xuan 	for (idx = 0; idx < 32; idx += 4)
10078f6c5dbSZiyang Xuan 		checksum ^= ((val >> idx) & 0xF);
10178f6c5dbSZiyang Xuan 
10278f6c5dbSZiyang Xuan 	return (checksum & 0xF);
10378f6c5dbSZiyang Xuan }
10478f6c5dbSZiyang Xuan 
10578f6c5dbSZiyang Xuan /**
10678f6c5dbSZiyang Xuan  * set_eq_cons_idx - write the cons idx to the hw
10778f6c5dbSZiyang Xuan  * @eq: The event queue to update the cons idx for
10878f6c5dbSZiyang Xuan  * @arm_state: indicate whether report interrupts when generate eq element
109dd93390eSXiaoyun Wang  */
11078f6c5dbSZiyang Xuan static void set_eq_cons_idx(struct hinic_eq *eq, u32 arm_state)
11178f6c5dbSZiyang Xuan {
11278f6c5dbSZiyang Xuan 	u32 eq_cons_idx, eq_wrap_ci, val;
11378f6c5dbSZiyang Xuan 	u32 addr = EQ_CONS_IDX_REG_ADDR(eq);
11478f6c5dbSZiyang Xuan 
11578f6c5dbSZiyang Xuan 	eq_wrap_ci = EQ_CONS_IDX(eq);
11678f6c5dbSZiyang Xuan 
11778f6c5dbSZiyang Xuan 	/* Read Modify Write */
11878f6c5dbSZiyang Xuan 	val = hinic_hwif_read_reg(eq->hwdev->hwif, addr);
11978f6c5dbSZiyang Xuan 
12078f6c5dbSZiyang Xuan 	val = EQ_CONS_IDX_CLEAR(val, CONS_IDX) &
12178f6c5dbSZiyang Xuan 		EQ_CONS_IDX_CLEAR(val, INT_ARMED) &
12278f6c5dbSZiyang Xuan 		EQ_CONS_IDX_CLEAR(val, XOR_CHKSUM);
12378f6c5dbSZiyang Xuan 
12478f6c5dbSZiyang Xuan 	/* Just aeq0 use int_arm mode for pmd drv to recv
12578f6c5dbSZiyang Xuan 	 * asyn event&mbox recv data
12678f6c5dbSZiyang Xuan 	 */
12778f6c5dbSZiyang Xuan 	if (eq->q_id == 0)
12878f6c5dbSZiyang Xuan 		eq_cons_idx = EQ_CONS_IDX_SET(eq_wrap_ci, CONS_IDX) |
12978f6c5dbSZiyang Xuan 			EQ_CONS_IDX_SET(arm_state, INT_ARMED);
13078f6c5dbSZiyang Xuan 	else
13178f6c5dbSZiyang Xuan 		eq_cons_idx = EQ_CONS_IDX_SET(eq_wrap_ci, CONS_IDX) |
13278f6c5dbSZiyang Xuan 			EQ_CONS_IDX_SET(HINIC_EQ_NOT_ARMED, INT_ARMED);
13378f6c5dbSZiyang Xuan 
13478f6c5dbSZiyang Xuan 	val |= eq_cons_idx;
13578f6c5dbSZiyang Xuan 
13678f6c5dbSZiyang Xuan 	val |= EQ_CONS_IDX_SET(eq_cons_idx_checksum_set(val), XOR_CHKSUM);
13778f6c5dbSZiyang Xuan 
13878f6c5dbSZiyang Xuan 	hinic_hwif_write_reg(eq->hwdev->hwif, addr, val);
13978f6c5dbSZiyang Xuan }
14078f6c5dbSZiyang Xuan 
14178f6c5dbSZiyang Xuan /**
14278f6c5dbSZiyang Xuan  * eq_update_ci - update the cons idx of event queue
14378f6c5dbSZiyang Xuan  * @eq: the event queue to update the cons idx for
144dd93390eSXiaoyun Wang  */
14578f6c5dbSZiyang Xuan void eq_update_ci(struct hinic_eq *eq)
14678f6c5dbSZiyang Xuan {
14778f6c5dbSZiyang Xuan 	set_eq_cons_idx(eq, HINIC_EQ_ARMED);
14878f6c5dbSZiyang Xuan }
14978f6c5dbSZiyang Xuan 
15078f6c5dbSZiyang Xuan /**
15178f6c5dbSZiyang Xuan  * set_eq_ctrls - setting eq's ctrls registers
15278f6c5dbSZiyang Xuan  * @eq: the event queue for setting
153dd93390eSXiaoyun Wang  */
154dd93390eSXiaoyun Wang static void set_aeq_ctrls(struct hinic_eq *eq)
15578f6c5dbSZiyang Xuan {
15678f6c5dbSZiyang Xuan 	struct hinic_hwif *hwif = eq->hwdev->hwif;
15778f6c5dbSZiyang Xuan 	struct irq_info *eq_irq = &eq->eq_irq;
15878f6c5dbSZiyang Xuan 	u32 addr, val, ctrl0, ctrl1, page_size_val, elem_size;
15978f6c5dbSZiyang Xuan 	u32 pci_intf_idx = HINIC_PCI_INTF_IDX(hwif);
16078f6c5dbSZiyang Xuan 
16178f6c5dbSZiyang Xuan 	/* set ctrl0 */
16278f6c5dbSZiyang Xuan 	addr = HINIC_CSR_AEQ_CTRL_0_ADDR(eq->q_id);
16378f6c5dbSZiyang Xuan 
16478f6c5dbSZiyang Xuan 	val = hinic_hwif_read_reg(hwif, addr);
16578f6c5dbSZiyang Xuan 
16678f6c5dbSZiyang Xuan 	val = AEQ_CTRL_0_CLEAR(val, INTR_IDX) &
16778f6c5dbSZiyang Xuan 		AEQ_CTRL_0_CLEAR(val, DMA_ATTR) &
16878f6c5dbSZiyang Xuan 		AEQ_CTRL_0_CLEAR(val, PCI_INTF_IDX) &
16978f6c5dbSZiyang Xuan 		AEQ_CTRL_0_CLEAR(val, INTR_MODE);
17078f6c5dbSZiyang Xuan 
17178f6c5dbSZiyang Xuan 	ctrl0 = AEQ_CTRL_0_SET(eq_irq->msix_entry_idx, INTR_IDX) |
17278f6c5dbSZiyang Xuan 		AEQ_CTRL_0_SET(AEQ_DMA_ATTR_DEFAULT, DMA_ATTR)	|
17378f6c5dbSZiyang Xuan 		AEQ_CTRL_0_SET(pci_intf_idx, PCI_INTF_IDX)	|
17478f6c5dbSZiyang Xuan 		AEQ_CTRL_0_SET(HINIC_INTR_MODE_ARMED, INTR_MODE);
17578f6c5dbSZiyang Xuan 
17678f6c5dbSZiyang Xuan 	val |= ctrl0;
17778f6c5dbSZiyang Xuan 
17878f6c5dbSZiyang Xuan 	hinic_hwif_write_reg(hwif, addr, val);
17978f6c5dbSZiyang Xuan 
18078f6c5dbSZiyang Xuan 	/* set ctrl1 */
18178f6c5dbSZiyang Xuan 	addr = HINIC_CSR_AEQ_CTRL_1_ADDR(eq->q_id);
18278f6c5dbSZiyang Xuan 
18378f6c5dbSZiyang Xuan 	page_size_val = EQ_SET_HW_PAGE_SIZE_VAL(eq);
18478f6c5dbSZiyang Xuan 	elem_size = EQ_SET_HW_ELEM_SIZE_VAL(eq);
18578f6c5dbSZiyang Xuan 
18678f6c5dbSZiyang Xuan 	ctrl1 = AEQ_CTRL_1_SET(eq->eq_len, LEN)		|
18778f6c5dbSZiyang Xuan 		AEQ_CTRL_1_SET(elem_size, ELEM_SIZE)	|
18878f6c5dbSZiyang Xuan 		AEQ_CTRL_1_SET(page_size_val, PAGE_SIZE);
18978f6c5dbSZiyang Xuan 
19078f6c5dbSZiyang Xuan 	hinic_hwif_write_reg(hwif, addr, ctrl1);
19178f6c5dbSZiyang Xuan }
19278f6c5dbSZiyang Xuan 
19378f6c5dbSZiyang Xuan /**
19478f6c5dbSZiyang Xuan  * aeq_elements_init - initialize all the elements in the aeq
19578f6c5dbSZiyang Xuan  * @eq: the event queue
19678f6c5dbSZiyang Xuan  * @init_val: value to init with it the elements
197dd93390eSXiaoyun Wang  */
19878f6c5dbSZiyang Xuan static void aeq_elements_init(struct hinic_eq *eq, u32 init_val)
19978f6c5dbSZiyang Xuan {
20078f6c5dbSZiyang Xuan 	struct hinic_aeq_elem *aeqe;
20178f6c5dbSZiyang Xuan 	u16 i;
20278f6c5dbSZiyang Xuan 
20378f6c5dbSZiyang Xuan 	for (i = 0; i < eq->eq_len; i++) {
20478f6c5dbSZiyang Xuan 		aeqe = GET_AEQ_ELEM(eq, i);
20578f6c5dbSZiyang Xuan 		aeqe->desc = cpu_to_be32(init_val);
20678f6c5dbSZiyang Xuan 	}
20778f6c5dbSZiyang Xuan 
20878f6c5dbSZiyang Xuan 	rte_wmb();	/* Write the init values */
20978f6c5dbSZiyang Xuan }
21078f6c5dbSZiyang Xuan 
21178f6c5dbSZiyang Xuan /**
21278f6c5dbSZiyang Xuan  * alloc_eq_pages - allocate the pages for the queue
21378f6c5dbSZiyang Xuan  * @eq: the event queue
214dd93390eSXiaoyun Wang  */
21578f6c5dbSZiyang Xuan static int alloc_eq_pages(struct hinic_eq *eq)
21678f6c5dbSZiyang Xuan {
21778f6c5dbSZiyang Xuan 	struct hinic_hwif *hwif = eq->hwdev->hwif;
21878f6c5dbSZiyang Xuan 	u32 init_val;
21978f6c5dbSZiyang Xuan 	u64 dma_addr_size, virt_addr_size;
22078f6c5dbSZiyang Xuan 	u16 pg_num, i;
22178f6c5dbSZiyang Xuan 	int err;
22278f6c5dbSZiyang Xuan 
22378f6c5dbSZiyang Xuan 	dma_addr_size = eq->num_pages * sizeof(*eq->dma_addr);
22478f6c5dbSZiyang Xuan 	virt_addr_size = eq->num_pages * sizeof(*eq->virt_addr);
22578f6c5dbSZiyang Xuan 
22678f6c5dbSZiyang Xuan 	eq->dma_addr = kzalloc(dma_addr_size, GFP_KERNEL);
22778f6c5dbSZiyang Xuan 	if (!eq->dma_addr) {
22878f6c5dbSZiyang Xuan 		PMD_DRV_LOG(ERR, "Allocate dma addr array failed");
22978f6c5dbSZiyang Xuan 		return -ENOMEM;
23078f6c5dbSZiyang Xuan 	}
23178f6c5dbSZiyang Xuan 
23278f6c5dbSZiyang Xuan 	eq->virt_addr = kzalloc(virt_addr_size, GFP_KERNEL);
23378f6c5dbSZiyang Xuan 	if (!eq->virt_addr) {
23478f6c5dbSZiyang Xuan 		PMD_DRV_LOG(ERR, "Allocate virt addr array failed");
23578f6c5dbSZiyang Xuan 		err = -ENOMEM;
23678f6c5dbSZiyang Xuan 		goto virt_addr_alloc_err;
23778f6c5dbSZiyang Xuan 	}
23878f6c5dbSZiyang Xuan 
23978f6c5dbSZiyang Xuan 	for (pg_num = 0; pg_num < eq->num_pages; pg_num++) {
24078f6c5dbSZiyang Xuan 		eq->virt_addr[pg_num] =
24178f6c5dbSZiyang Xuan 			(u8 *)dma_zalloc_coherent_aligned(eq->hwdev,
24278f6c5dbSZiyang Xuan 					eq->page_size, &eq->dma_addr[pg_num],
2431b7b9f17SXiaoyun Wang 					SOCKET_ID_ANY);
24478f6c5dbSZiyang Xuan 		if (!eq->virt_addr[pg_num]) {
24578f6c5dbSZiyang Xuan 			err = -ENOMEM;
24678f6c5dbSZiyang Xuan 			goto dma_alloc_err;
24778f6c5dbSZiyang Xuan 		}
24878f6c5dbSZiyang Xuan 
24978f6c5dbSZiyang Xuan 		hinic_hwif_write_reg(hwif,
25078f6c5dbSZiyang Xuan 				     HINIC_EQ_HI_PHYS_ADDR_REG(eq->type,
25178f6c5dbSZiyang Xuan 				     eq->q_id, pg_num),
25278f6c5dbSZiyang Xuan 				     upper_32_bits(eq->dma_addr[pg_num]));
25378f6c5dbSZiyang Xuan 
25478f6c5dbSZiyang Xuan 		hinic_hwif_write_reg(hwif,
25578f6c5dbSZiyang Xuan 				     HINIC_EQ_LO_PHYS_ADDR_REG(eq->type,
25678f6c5dbSZiyang Xuan 				     eq->q_id, pg_num),
25778f6c5dbSZiyang Xuan 				     lower_32_bits(eq->dma_addr[pg_num]));
25878f6c5dbSZiyang Xuan 	}
25978f6c5dbSZiyang Xuan 
26078f6c5dbSZiyang Xuan 	init_val = EQ_WRAPPED(eq);
26178f6c5dbSZiyang Xuan 
26278f6c5dbSZiyang Xuan 	aeq_elements_init(eq, init_val);
26378f6c5dbSZiyang Xuan 
26478f6c5dbSZiyang Xuan 	return 0;
26578f6c5dbSZiyang Xuan 
26678f6c5dbSZiyang Xuan dma_alloc_err:
26778f6c5dbSZiyang Xuan 	for (i = 0; i < pg_num; i++)
26878f6c5dbSZiyang Xuan 		dma_free_coherent(eq->hwdev, eq->page_size,
26978f6c5dbSZiyang Xuan 				  eq->virt_addr[i], eq->dma_addr[i]);
27078f6c5dbSZiyang Xuan 
27178f6c5dbSZiyang Xuan virt_addr_alloc_err:
27278f6c5dbSZiyang Xuan 	kfree(eq->dma_addr);
27378f6c5dbSZiyang Xuan 	return err;
27478f6c5dbSZiyang Xuan }
27578f6c5dbSZiyang Xuan 
27678f6c5dbSZiyang Xuan /**
27778f6c5dbSZiyang Xuan  * free_eq_pages - free the pages of the queue
27878f6c5dbSZiyang Xuan  * @eq: the event queue
279dd93390eSXiaoyun Wang  */
28078f6c5dbSZiyang Xuan static void free_eq_pages(struct hinic_eq *eq)
28178f6c5dbSZiyang Xuan {
28278f6c5dbSZiyang Xuan 	struct hinic_hwdev *hwdev = eq->hwdev;
28378f6c5dbSZiyang Xuan 	u16 pg_num;
28478f6c5dbSZiyang Xuan 
28578f6c5dbSZiyang Xuan 	for (pg_num = 0; pg_num < eq->num_pages; pg_num++)
28678f6c5dbSZiyang Xuan 		dma_free_coherent(hwdev, eq->page_size,
28778f6c5dbSZiyang Xuan 				  eq->virt_addr[pg_num],
28878f6c5dbSZiyang Xuan 				  eq->dma_addr[pg_num]);
28978f6c5dbSZiyang Xuan 
29078f6c5dbSZiyang Xuan 	kfree(eq->virt_addr);
29178f6c5dbSZiyang Xuan 	kfree(eq->dma_addr);
29278f6c5dbSZiyang Xuan }
29378f6c5dbSZiyang Xuan 
29478f6c5dbSZiyang Xuan #define MSIX_ENTRY_IDX_0 (0)
29578f6c5dbSZiyang Xuan 
29678f6c5dbSZiyang Xuan /**
297dd93390eSXiaoyun Wang  * init_aeq - initialize aeq
29878f6c5dbSZiyang Xuan  * @eq:	the event queue
29978f6c5dbSZiyang Xuan  * @hwdev: the pointer to the private hardware device object
30078f6c5dbSZiyang Xuan  * @q_id: Queue id number
30178f6c5dbSZiyang Xuan  * @q_len: the number of EQ elements
30278f6c5dbSZiyang Xuan  * @type: the type of the event queue, ceq or aeq
30378f6c5dbSZiyang Xuan  * @page_size: the page size of the event queue
30478f6c5dbSZiyang Xuan  * @entry: msix entry associated with the event queue
30578f6c5dbSZiyang Xuan  * Return: 0 - Success, Negative - failure
306dd93390eSXiaoyun Wang  */
307dd93390eSXiaoyun Wang static int init_aeq(struct hinic_eq *eq, struct hinic_hwdev *hwdev, u16 q_id,
308dd93390eSXiaoyun Wang 		   u16 q_len, u32 page_size,
30978f6c5dbSZiyang Xuan 		   __rte_unused struct irq_info *entry)
31078f6c5dbSZiyang Xuan {
31178f6c5dbSZiyang Xuan 	int err = 0;
31278f6c5dbSZiyang Xuan 
31378f6c5dbSZiyang Xuan 	eq->hwdev = hwdev;
31478f6c5dbSZiyang Xuan 	eq->q_id = q_id;
315dd93390eSXiaoyun Wang 	eq->type = HINIC_AEQ;
31678f6c5dbSZiyang Xuan 	eq->page_size = page_size;
31778f6c5dbSZiyang Xuan 	eq->eq_len = q_len;
31878f6c5dbSZiyang Xuan 
31978f6c5dbSZiyang Xuan 	/* clear eq_len to force eqe drop in hardware */
32078f6c5dbSZiyang Xuan 	hinic_hwif_write_reg(eq->hwdev->hwif,
32178f6c5dbSZiyang Xuan 			     HINIC_CSR_AEQ_CTRL_1_ADDR(eq->q_id), 0);
322dd93390eSXiaoyun Wang 
323dd93390eSXiaoyun Wang 	/* Clear PI and CI, also clear the ARM bit */
324dd93390eSXiaoyun Wang 	hinic_hwif_write_reg(eq->hwdev->hwif, EQ_CONS_IDX_REG_ADDR(eq), 0);
325dd93390eSXiaoyun Wang 	hinic_hwif_write_reg(eq->hwdev->hwif, EQ_PROD_IDX_REG_ADDR(eq), 0);
32678f6c5dbSZiyang Xuan 
32778f6c5dbSZiyang Xuan 	eq->cons_idx = 0;
32878f6c5dbSZiyang Xuan 	eq->wrapped = 0;
32978f6c5dbSZiyang Xuan 
330dd93390eSXiaoyun Wang 	eq->elem_size = HINIC_AEQE_SIZE;
33178f6c5dbSZiyang Xuan 	eq->num_pages = GET_EQ_NUM_PAGES(eq, page_size);
33278f6c5dbSZiyang Xuan 	eq->num_elem_in_pg = GET_EQ_NUM_ELEMS(eq, page_size);
33378f6c5dbSZiyang Xuan 
33478f6c5dbSZiyang Xuan 	if (eq->num_elem_in_pg & (eq->num_elem_in_pg - 1)) {
33578f6c5dbSZiyang Xuan 		PMD_DRV_LOG(ERR, "Number element in eq page is not power of 2");
33678f6c5dbSZiyang Xuan 		return -EINVAL;
33778f6c5dbSZiyang Xuan 	}
33878f6c5dbSZiyang Xuan 
33978f6c5dbSZiyang Xuan 	if (eq->num_pages > HINIC_EQ_MAX_PAGES) {
34078f6c5dbSZiyang Xuan 		PMD_DRV_LOG(ERR, "Too many pages for eq, num_pages: %d",
34178f6c5dbSZiyang Xuan 			eq->num_pages);
34278f6c5dbSZiyang Xuan 		return -EINVAL;
34378f6c5dbSZiyang Xuan 	}
34478f6c5dbSZiyang Xuan 
34578f6c5dbSZiyang Xuan 	err = alloc_eq_pages(eq);
34678f6c5dbSZiyang Xuan 	if (err) {
34778f6c5dbSZiyang Xuan 		PMD_DRV_LOG(ERR, "Allocate pages for eq failed");
34878f6c5dbSZiyang Xuan 		return err;
34978f6c5dbSZiyang Xuan 	}
35078f6c5dbSZiyang Xuan 
35178f6c5dbSZiyang Xuan 	/* pmd use MSIX_ENTRY_IDX_0 */
35278f6c5dbSZiyang Xuan 	eq->eq_irq.msix_entry_idx = MSIX_ENTRY_IDX_0;
35378f6c5dbSZiyang Xuan 
354dd93390eSXiaoyun Wang 	set_aeq_ctrls(eq);
35578f6c5dbSZiyang Xuan 	set_eq_cons_idx(eq, HINIC_EQ_ARMED);
35678f6c5dbSZiyang Xuan 
35778f6c5dbSZiyang Xuan 	if (eq->q_id == 0)
35878f6c5dbSZiyang Xuan 		hinic_set_msix_state(hwdev, 0, HINIC_MSIX_ENABLE);
35978f6c5dbSZiyang Xuan 
36078f6c5dbSZiyang Xuan 	eq->poll_retry_nr = HINIC_RETRY_NUM;
36178f6c5dbSZiyang Xuan 
36278f6c5dbSZiyang Xuan 	return 0;
36378f6c5dbSZiyang Xuan }
36478f6c5dbSZiyang Xuan 
36578f6c5dbSZiyang Xuan /**
366dd93390eSXiaoyun Wang  * remove_aeq - remove aeq
36778f6c5dbSZiyang Xuan  * @eq:	the event queue
368dd93390eSXiaoyun Wang  */
369dd93390eSXiaoyun Wang static void remove_aeq(struct hinic_eq *eq)
37078f6c5dbSZiyang Xuan {
37178f6c5dbSZiyang Xuan 	struct irq_info *entry = &eq->eq_irq;
37278f6c5dbSZiyang Xuan 
37378f6c5dbSZiyang Xuan 	if (eq->q_id == 0)
37478f6c5dbSZiyang Xuan 		hinic_set_msix_state(eq->hwdev, entry->msix_entry_idx,
37578f6c5dbSZiyang Xuan 				     HINIC_MSIX_DISABLE);
37678f6c5dbSZiyang Xuan 
37778f6c5dbSZiyang Xuan 	/* clear eq_len to avoid hw access host memory */
37878f6c5dbSZiyang Xuan 	hinic_hwif_write_reg(eq->hwdev->hwif,
37978f6c5dbSZiyang Xuan 			     HINIC_CSR_AEQ_CTRL_1_ADDR(eq->q_id), 0);
38078f6c5dbSZiyang Xuan 
38178f6c5dbSZiyang Xuan 	/* update cons_idx to avoid invalid interrupt */
38278f6c5dbSZiyang Xuan 	eq->cons_idx = (u16)hinic_hwif_read_reg(eq->hwdev->hwif,
38378f6c5dbSZiyang Xuan 						EQ_PROD_IDX_REG_ADDR(eq));
38478f6c5dbSZiyang Xuan 	set_eq_cons_idx(eq, HINIC_EQ_NOT_ARMED);
38578f6c5dbSZiyang Xuan 
38678f6c5dbSZiyang Xuan 	free_eq_pages(eq);
38778f6c5dbSZiyang Xuan }
38878f6c5dbSZiyang Xuan 
38978f6c5dbSZiyang Xuan /**
39078f6c5dbSZiyang Xuan  * hinic_aeqs_init - init all the aeqs
39178f6c5dbSZiyang Xuan  * @hwdev: the pointer to the private hardware device object
39278f6c5dbSZiyang Xuan  * @num_aeqs: number of aeq
39378f6c5dbSZiyang Xuan  * @msix_entries: msix entries associated with the event queues
39478f6c5dbSZiyang Xuan  * Return: 0 - Success, Negative - failure
395dd93390eSXiaoyun Wang  */
39678f6c5dbSZiyang Xuan static int
39778f6c5dbSZiyang Xuan hinic_aeqs_init(struct hinic_hwdev *hwdev, u16 num_aeqs,
39878f6c5dbSZiyang Xuan 		struct irq_info *msix_entries)
39978f6c5dbSZiyang Xuan {
40078f6c5dbSZiyang Xuan 	struct hinic_aeqs *aeqs;
40178f6c5dbSZiyang Xuan 	int err;
40278f6c5dbSZiyang Xuan 	u16 i, q_id;
40378f6c5dbSZiyang Xuan 
40478f6c5dbSZiyang Xuan 	aeqs = kzalloc(sizeof(*aeqs), GFP_KERNEL);
40578f6c5dbSZiyang Xuan 	if (!aeqs)
40678f6c5dbSZiyang Xuan 		return -ENOMEM;
40778f6c5dbSZiyang Xuan 
40878f6c5dbSZiyang Xuan 	hwdev->aeqs = aeqs;
40978f6c5dbSZiyang Xuan 	aeqs->hwdev = hwdev;
41078f6c5dbSZiyang Xuan 	aeqs->num_aeqs = num_aeqs;
41178f6c5dbSZiyang Xuan 
41278f6c5dbSZiyang Xuan 	for (q_id = HINIC_AEQN_START; q_id < num_aeqs; q_id++) {
413dd93390eSXiaoyun Wang 		err = init_aeq(&aeqs->aeq[q_id], hwdev, q_id,
414dd93390eSXiaoyun Wang 			      HINIC_DEFAULT_AEQ_LEN, HINIC_EQ_PAGE_SIZE,
415dd93390eSXiaoyun Wang 			      &msix_entries[q_id]);
41678f6c5dbSZiyang Xuan 		if (err) {
41778f6c5dbSZiyang Xuan 			PMD_DRV_LOG(ERR, "Init aeq %d failed", q_id);
41878f6c5dbSZiyang Xuan 			goto init_aeq_err;
41978f6c5dbSZiyang Xuan 		}
42078f6c5dbSZiyang Xuan 	}
42178f6c5dbSZiyang Xuan 
42278f6c5dbSZiyang Xuan 	return 0;
42378f6c5dbSZiyang Xuan 
42478f6c5dbSZiyang Xuan init_aeq_err:
42578f6c5dbSZiyang Xuan 	for (i = 0; i < q_id; i++)
426dd93390eSXiaoyun Wang 		remove_aeq(&aeqs->aeq[i]);
42778f6c5dbSZiyang Xuan 
42878f6c5dbSZiyang Xuan 	kfree(aeqs);
42978f6c5dbSZiyang Xuan 
43078f6c5dbSZiyang Xuan 	return err;
43178f6c5dbSZiyang Xuan }
43278f6c5dbSZiyang Xuan 
43378f6c5dbSZiyang Xuan /**
43478f6c5dbSZiyang Xuan  * hinic_aeqs_free - free all the aeqs
43578f6c5dbSZiyang Xuan  * @hwdev: the pointer to the private hardware device object
436dd93390eSXiaoyun Wang  */
43778f6c5dbSZiyang Xuan static void hinic_aeqs_free(struct hinic_hwdev *hwdev)
43878f6c5dbSZiyang Xuan {
43978f6c5dbSZiyang Xuan 	struct hinic_aeqs *aeqs = hwdev->aeqs;
44078f6c5dbSZiyang Xuan 	u16 q_id;
44178f6c5dbSZiyang Xuan 
44278f6c5dbSZiyang Xuan 	/* hinic pmd use aeq[1~3], aeq[0] used in kernel only */
44378f6c5dbSZiyang Xuan 	for (q_id = HINIC_AEQN_START; q_id < aeqs->num_aeqs ; q_id++)
444dd93390eSXiaoyun Wang 		remove_aeq(&aeqs->aeq[q_id]);
44578f6c5dbSZiyang Xuan 
44678f6c5dbSZiyang Xuan 	kfree(aeqs);
44778f6c5dbSZiyang Xuan }
44878f6c5dbSZiyang Xuan 
44978f6c5dbSZiyang Xuan void hinic_dump_aeq_info(struct hinic_hwdev *hwdev)
45078f6c5dbSZiyang Xuan {
45178f6c5dbSZiyang Xuan 	struct hinic_eq *eq;
45278f6c5dbSZiyang Xuan 	u32 addr, ci, pi;
45378f6c5dbSZiyang Xuan 	int q_id;
45478f6c5dbSZiyang Xuan 
45578f6c5dbSZiyang Xuan 	for (q_id = 0; q_id < hwdev->aeqs->num_aeqs; q_id++) {
45678f6c5dbSZiyang Xuan 		eq = &hwdev->aeqs->aeq[q_id];
45778f6c5dbSZiyang Xuan 		addr = EQ_CONS_IDX_REG_ADDR(eq);
45878f6c5dbSZiyang Xuan 		ci = hinic_hwif_read_reg(hwdev->hwif, addr);
45978f6c5dbSZiyang Xuan 		addr = EQ_PROD_IDX_REG_ADDR(eq);
46078f6c5dbSZiyang Xuan 		pi = hinic_hwif_read_reg(hwdev->hwif, addr);
46178f6c5dbSZiyang Xuan 		PMD_DRV_LOG(ERR, "aeq id: %d, ci: 0x%x, pi: 0x%x",
46278f6c5dbSZiyang Xuan 			q_id, ci, pi);
46378f6c5dbSZiyang Xuan 	}
46478f6c5dbSZiyang Xuan }
46578f6c5dbSZiyang Xuan 
46678f6c5dbSZiyang Xuan int hinic_comm_aeqs_init(struct hinic_hwdev *hwdev)
46778f6c5dbSZiyang Xuan {
46878f6c5dbSZiyang Xuan 	int rc;
46978f6c5dbSZiyang Xuan 	u16 num_aeqs;
47078f6c5dbSZiyang Xuan 	struct irq_info aeq_irqs[HINIC_MAX_AEQS];
47178f6c5dbSZiyang Xuan 
47278f6c5dbSZiyang Xuan 	num_aeqs = HINIC_HWIF_NUM_AEQS(hwdev->hwif);
47317ff26b6SGuoyang Zhou 	if (num_aeqs < HINIC_MIN_AEQS) {
474*f665790aSDavid Marchand 		PMD_DRV_LOG(ERR, "PMD need %d AEQs, Chip has %d",
47517ff26b6SGuoyang Zhou 				HINIC_MIN_AEQS, num_aeqs);
47617ff26b6SGuoyang Zhou 		return -EINVAL;
47778f6c5dbSZiyang Xuan 	}
47878f6c5dbSZiyang Xuan 
47978f6c5dbSZiyang Xuan 	memset(aeq_irqs, 0, sizeof(aeq_irqs));
48078f6c5dbSZiyang Xuan 	rc = hinic_aeqs_init(hwdev, num_aeqs, aeq_irqs);
48178f6c5dbSZiyang Xuan 	if (rc != HINIC_OK)
48278f6c5dbSZiyang Xuan 		PMD_DRV_LOG(ERR, "Initialize aeqs failed, rc: %d", rc);
48378f6c5dbSZiyang Xuan 
48478f6c5dbSZiyang Xuan 	return rc;
48578f6c5dbSZiyang Xuan }
48678f6c5dbSZiyang Xuan 
48778f6c5dbSZiyang Xuan void hinic_comm_aeqs_free(struct hinic_hwdev *hwdev)
48878f6c5dbSZiyang Xuan {
48978f6c5dbSZiyang Xuan 	hinic_aeqs_free(hwdev);
49078f6c5dbSZiyang Xuan }
491