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